SCIP

    Solving Constraint Integer Programs

    cons_nonlinear.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 cons_nonlinear.c
    26 * @ingroup DEFPLUGINS_CONS
    27 * @brief constraint handler for nonlinear constraints specified by algebraic expressions
    28 * @author Ksenia Bestuzheva
    29 * @author Benjamin Mueller
    30 * @author Felipe Serrano
    31 * @author Stefan Vigerske
    32 */
    33
    34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    35
    36#ifdef SCIP_DEBUG
    37#define ENFO_LOGGING
    38#endif
    39
    40/* enable to get log output for enforcement */
    41/* #define ENFO_LOGGING */
    42/* define to get enforcement logging into file */
    43/* #define ENFOLOGFILE "consexpr_enfo.log" */
    44
    45/* define to get more debug output from domain propagation */
    46/* #define DEBUG_PROP */
    47
    48/*lint -e440*/
    49/*lint -e441*/
    50/*lint -e528*/
    51/*lint -e666*/
    52/*lint -e777*/
    53/*lint -e866*/
    54
    55#include <ctype.h>
    56#include "scip/cons_nonlinear.h"
    57#include "scip/nlhdlr.h"
    58#include "scip/expr_var.h"
    59#include "scip/expr_varidx.h"
    60#include "scip/expr_abs.h"
    61#include "scip/expr_sum.h"
    62#include "scip/expr_value.h"
    63#include "scip/expr_pow.h"
    64#include "scip/expr_trig.h"
    65#include "scip/nlhdlr_convex.h"
    66#include "scip/cons_linear.h"
    67#include "scip/cons_varbound.h"
    68#include "scip/cons_and.h"
    70#include "scip/cons_setppc.h"
    71#include "scip/heur_subnlp.h"
    72#include "scip/heur_trysol.h"
    73#include "scip/lapack_calls.h"
    74#include "scip/debug.h"
    75#include "scip/dialog_default.h"
    76#include "scip/scip_expr.h"
    77#include "scip/symmetry_graph.h"
    78#include "scip/prop_symmetry.h"
    80#include "scip/pub_misc_sort.h"
    81#include "scip/scip_datatree.h"
    82
    83/* fundamental constraint handler properties */
    84#define CONSHDLR_NAME "nonlinear"
    85#define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
    86#define CONSHDLR_ENFOPRIORITY 50 /**< priority of the constraint handler for constraint enforcing */
    87#define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
    88#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
    89 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
    90#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
    91
    92/* optional constraint handler properties */
    93#define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
    94#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
    95#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
    96
    97#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
    98#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
    99#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
    100
    101#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
    102#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
    103
    104/* properties of the nonlinear constraint handler statistics table */
    105#define TABLE_NAME_NONLINEAR "cons_nonlinear"
    106#define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
    107#define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
    108#define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
    109
    110/* properties of the nonlinear handler statistics table */
    111#define TABLE_NAME_NLHDLR "nlhdlr"
    112#define TABLE_DESC_NLHDLR "nonlinear handler statistics"
    113#define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
    114#define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
    115
    116#define DIALOG_NAME "nlhdlrs"
    117#define DIALOG_DESC "display nonlinear handlers"
    118#define DIALOG_ISSUBMENU FALSE
    119
    120#define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
    121#define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
    122#define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
    123#define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
    124
    125#define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
    126
    127#define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
    128
    129/** translate from one value of infinity to another
    130 *
    131 * if val is &ge; infty1, then give infty2, else give val
    132 */
    133#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
    134
    135/** translates x to 2^x for non-negative integer x */
    136#define POWEROFTWO(x) (0x1u << (x))
    137
    138#ifdef ENFO_LOGGING
    139#define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
    140FILE* enfologfile = NULL;
    141#else
    142#define ENFOLOG(x)
    143#endif
    144
    145/*
    146 * Data structures
    147 */
    148
    149/** enforcement data of an expression */
    150typedef struct
    151{
    152 SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
    153 SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
    154 SCIP_NLHDLR_METHOD nlhdlrparticipation;/**< methods where nonlinear handler participates */
    155 SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
    156 SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
    157 SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
    158 SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
    159} EXPRENFO;
    160
    161/** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
    162struct SCIP_Expr_OwnerData
    163{
    164 SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
    165
    166 /* locks and monotonicity */
    167 int nlockspos; /**< positive locks counter */
    168 int nlocksneg; /**< negative locks counter */
    169 SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
    170 int monotonicitysize; /**< length of monotonicity array */
    171
    172 /* propagation (in addition to activity that is stored in expr) */
    173 SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
    174 unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
    175 SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
    176
    177 /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
    178 EXPRENFO** enfos; /**< enforcements */
    179 int nenfos; /**< number of enforcements, or -1 if not initialized */
    180 unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
    181 unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
    182 unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
    183 unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
    184 SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
    185
    186 /* branching */
    187 SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
    188 SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
    189 int nviolscores; /**< number of violation scores stored for this expression */
    190 unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
    191
    192 /* additional data for variable expressions (TODO move into sub-struct?) */
    193 SCIP_CONS** conss; /**< constraints in which this variable appears */
    194 int nconss; /**< current number of constraints in conss */
    195 int consssize; /**< length of conss array */
    196 SCIP_Bool consssorted; /**< is the array of constraints sorted */
    197
    198 int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
    199};
    200
    201/** constraint data for nonlinear constraints */
    202struct SCIP_ConsData
    203{
    204 /* data that defines the constraint: expression and sides */
    205 SCIP_EXPR* expr; /**< expression that represents this constraint */
    206 SCIP_Real lhs; /**< left-hand side */
    207 SCIP_Real rhs; /**< right-hand side */
    208
    209 /* variables */
    210 SCIP_EXPR** varexprs; /**< array containing all variable expressions */
    211 int nvarexprs; /**< total number of variable expressions */
    212 SCIP_Bool catchedevents; /**< do we catch events on variables? */
    213
    214 /* constraint violation */
    215 SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
    216 SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
    217 SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
    218 SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
    219
    220 /* status flags */
    221 unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
    222 unsigned int issimplified:1; /**< did we simplify the expression tree already? */
    223
    224 /* locks */
    225 int nlockspos; /**< number of positive locks */
    226 int nlocksneg; /**< number of negative locks */
    227
    228 /* repair infeasible solutions */
    229 SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
    230 SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
    231 SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
    232 SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
    233
    234 /* miscellaneous */
    235 SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
    236 SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
    237 int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
    238};
    239
    240/** constraint upgrade method */
    241typedef struct
    242{
    243 SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
    244 int priority; /**< priority of upgrading method */
    245 SCIP_Bool active; /**< is upgrading enabled */
    247
    248/** constraint handler data */
    249struct SCIP_ConshdlrData
    250{
    251 /* nonlinear handler */
    252 SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
    253 int nnlhdlrs; /**< number of nonlinear handlers */
    254 int nlhdlrssize; /**< size of nlhdlrs array */
    255 SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
    256 SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
    257 SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
    258
    259 /* constraint upgrades */
    260 CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
    261 int consupgradessize; /**< size of consupgrades array */
    262 int nconsupgrades; /**< number of constraint upgrade methods */
    263
    264 /* other plugins */
    265 SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
    266 SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
    267 SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
    268
    269 /* tags and counters */
    270 int auxvarid; /**< unique id for the next auxiliary variable */
    271 SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
    272 SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
    273 SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
    274 unsigned int enforound; /**< total number of enforcement calls, including current one */
    275 int lastconsindex; /**< last used consindex, plus one */
    276
    277 /* activity intervals and domain propagation */
    278 SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
    279 SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
    280 SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
    281 SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
    282 unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
    283
    284 /* parameters */
    285 int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
    286 SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
    287 char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
    288 SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
    289 SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
    290 SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
    291 SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
    292 SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
    293 SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
    294 SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
    295 int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
    296 SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
    297 SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
    298 SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
    299 SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
    300 SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
    301 SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
    302 SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
    303 SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
    304 SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
    305 char rownotremovable; /**< whether to make rows to be non-removable in the node where they are added (can prevent some cycling): 'o'ff, in 'e'nforcement only, 'a'lways */
    306 char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
    307 char checkvarlocks; /**< whether variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction) */
    308 int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
    309 SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
    310 SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
    311 SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
    312 SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
    313 SCIP_Real branchfracweight; /**< weight by how much to consider fractionality of integer variables in branching score for spatial branching */
    314 SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
    315 SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
    316 SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
    317 SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
    318 char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
    319 char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
    320 SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
    321 SCIP_Real branchmixfractional; /**< minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables */
    322 char linearizeheursol; /**< whether tight linearizations of nonlinear constraints should be added to cutpool when some heuristics finds a new solution ('o'ff, on new 'i'ncumbents, on 'e'very solution) */
    323 SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
    324
    325 /* statistics */
    326 SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
    327 SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
    328 SCIP_Longint ndesperatetightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing because we didn't know anything better */
    329 SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
    330 SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
    331 SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
    332 SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
    333 SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
    334
    335 /* facets of envelops of vertex-polyhedral functions */
    336 SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
    337 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
    338
    339 /* hashing of bilinear terms */
    340 SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
    341 SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
    342 int nbilinterms; /**< total number of bilinear terms */
    343 int bilintermssize; /**< size of bilinterms array */
    344 int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
    345
    346 /* branching */
    347 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
    348 char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
    349
    350 /* misc */
    351 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
    352 SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
    353 int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
    354};
    355
    356/** branching candidate with various scores */
    357typedef struct
    358{
    359 SCIP_EXPR* expr; /**< expression that holds branching candidate, NULL if candidate is due to fractionality of integer variable */
    360 SCIP_VAR* var; /**< variable that is branching candidate */
    361 SCIP_Real auxviol; /**< aux-violation score of candidate */
    362 SCIP_Real domain; /**< domain score of candidate */
    363 SCIP_Real dual; /**< dual score of candidate */
    364 SCIP_Real pscost; /**< pseudo-cost score of candidate */
    365 SCIP_Real vartype; /**< variable type score of candidate */
    366 SCIP_Real fractionality; /**< fractionality score of candidate */
    367 SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
    368} BRANCHCAND;
    369
    370/*
    371 * Local methods
    372 */
    373
    374/* forward declaration */
    375static
    377 SCIP* scip, /**< SCIP data structure */
    378 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    379 SCIP_EXPR* rootexpr, /**< expression */
    380 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
    381 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
    382 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
    383 );
    384
    385/** frees auxiliary variables of expression, if any */
    386static
    388 SCIP* scip, /**< SCIP data structure */
    389 SCIP_EXPR* expr /**< expression which auxvar to free, if any */
    390 )
    391{
    392 SCIP_EXPR_OWNERDATA* mydata;
    393
    394 assert(scip != NULL);
    395 assert(expr != NULL);
    396
    397 mydata = SCIPexprGetOwnerData(expr);
    398 assert(mydata != NULL);
    399
    400 if( mydata->auxvar == NULL )
    401 return SCIP_OKAY;
    402
    403 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
    404
    405 /* remove variable locks
    406 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
    407 */
    408 SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
    409
    410 /* release auxiliary variable */
    411 SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
    412 assert(mydata->auxvar == NULL);
    413
    414 return SCIP_OKAY;
    415}
    416
    417/** frees data used for enforcement of expression, that is, nonlinear handlers
    418 *
    419 * can also clear indicators whether expr needs enforcement methods, that is,
    420 * free an associated auxiliary variable and reset the nactivityuses counts
    421 */
    422static
    424 SCIP* scip, /**< SCIP data structure */
    425 SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
    426 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
    427 )
    428{
    429 SCIP_EXPR_OWNERDATA* mydata;
    430 int e;
    431
    432 mydata = SCIPexprGetOwnerData(expr);
    433 assert(mydata != NULL);
    434
    435 if( freeauxvar )
    436 {
    437 /* free auxiliary variable */
    438 SCIP_CALL( freeAuxVar(scip, expr) );
    439 assert(mydata->auxvar == NULL);
    440
    441 /* reset count on activity and auxvar usage */
    442 mydata->nactivityusesprop = 0;
    443 mydata->nactivityusessepa = 0;
    444 mydata->nauxvaruses = 0;
    445 }
    446
    447 /* free data stored by nonlinear handlers */
    448 for( e = 0; e < mydata->nenfos; ++e )
    449 {
    450 SCIP_NLHDLR* nlhdlr;
    451
    452 assert(mydata->enfos[e] != NULL);
    453
    454 nlhdlr = mydata->enfos[e]->nlhdlr;
    455 assert(nlhdlr != NULL);
    456
    457 if( mydata->enfos[e]->issepainit )
    458 {
    459 /* call the separation deinitialization callback of the nonlinear handler */
    460 SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
    461 mydata->enfos[e]->issepainit = FALSE;
    462 }
    463
    464 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
    465 if( mydata->enfos[e]->nlhdlrexprdata != NULL )
    466 {
    467 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
    468 assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
    469 }
    470
    471 /* free enfo data */
    472 SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
    473 }
    474
    475 /* free array with enfo data */
    476 SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
    477
    478 /* we need to look at this expression in detect again */
    479 mydata->nenfos = -1;
    480
    481 return SCIP_OKAY;
    482}
    483
    484/** callback that frees data that this conshdlr stored in an expression */
    485static
    487{
    488 assert(scip != NULL);
    489 assert(expr != NULL);
    490 assert(ownerdata != NULL);
    491 assert(*ownerdata != NULL);
    492
    493 /* expression should not be locked anymore */
    494 assert((*ownerdata)->nlockspos == 0);
    495 assert((*ownerdata)->nlocksneg == 0);
    496
    497 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
    498
    499 /* expression should not be enforced anymore */
    500 assert((*ownerdata)->nenfos <= 0);
    501 assert((*ownerdata)->auxvar == NULL);
    502
    503 if( SCIPisExprVar(scip, expr) )
    504 {
    505 SCIP_CONSHDLRDATA* conshdlrdata;
    506 SCIP_VAR* var;
    507
    508 /* there should be no constraints left that still use this variable */
    509 assert((*ownerdata)->nconss == 0);
    510 /* thus, there should also be no variable event catched (via this exprhdlr) */
    511 assert((*ownerdata)->filterpos == -1);
    512
    513 SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
    514
    515 /* update var2expr hashmap in conshdlrdata */
    516 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
    517 assert(conshdlrdata != NULL);
    518
    519 var = SCIPgetVarExprVar(expr);
    520 assert(var != NULL);
    521
    522 /* remove var -> expr map from hashmap if present
    523 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
    524 * if variable-expression stored for var is different, then also do nothing)
    525 */
    526 if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
    527 {
    528 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
    529 }
    530 }
    531
    532 SCIPfreeBlockMemory(scip, ownerdata);
    533
    534 return SCIP_OKAY;
    535}
    536
    537static
    539{ /*lint --e{715}*/
    540 assert(ownerdata != NULL);
    541
    542 /* print nl handlers associated to expr */
    543 if( ownerdata->nenfos > 0 )
    544 {
    545 int i;
    546 SCIPinfoMessage(scip, file, " {");
    547
    548 for( i = 0; i < ownerdata->nenfos; ++i )
    549 {
    550 SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
    551 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
    552 SCIPinfoMessage(scip, file, "a");
    553 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
    554 SCIPinfoMessage(scip, file, "u");
    555 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
    556 SCIPinfoMessage(scip, file, "o");
    557 if( i < ownerdata->nenfos-1 )
    558 SCIPinfoMessage(scip, file, ", ");
    559 }
    560
    561 SCIPinfoMessage(scip, file, "}");
    562 }
    563
    564 /* print aux var associated to expr */
    565 if( ownerdata->auxvar != NULL )
    566 {
    567 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
    568 }
    569 SCIPinfoMessage(scip, file, "\n");
    570
    571 return SCIP_OKAY;
    572}
    573
    574/** possibly reevaluates and then returns the activity of the expression
    575 *
    576 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
    577 */
    578static
    580{
    581 SCIP_CONSHDLRDATA* conshdlrdata;
    582
    583 assert(scip != NULL);
    584 assert(expr != NULL);
    585 assert(ownerdata != NULL);
    586
    587 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    588 assert(conshdlrdata != NULL);
    589
    590 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
    591 {
    592 /* update activity of expression */
    593 SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
    594
    595 assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
    596 }
    597
    598 return SCIP_OKAY;
    599}
    600
    601/** callback that creates data that this conshdlr wants to store in an expression */
    602static
    604{
    605 assert(scip != NULL);
    606 assert(expr != NULL);
    607 assert(ownerdata != NULL);
    608
    610 (*ownerdata)->nenfos = -1;
    611 (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
    612
    613 if( SCIPisExprVar(scip, expr) )
    614 {
    615 SCIP_CONSHDLRDATA* conshdlrdata;
    616 SCIP_VAR* var;
    617
    618 (*ownerdata)->filterpos = -1;
    619
    620 /* add to var2expr hashmap if not having expr for var yet */
    621
    622 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
    623 assert(conshdlrdata != NULL);
    624
    625 var = SCIPgetVarExprVar(expr);
    626
    627 if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
    628 {
    629 /* store the variable expression in the hashmap */
    630 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
    631 }
    632 else
    633 {
    634 /* if expr was just created, then it shouldn't already be stored as image of var */
    635 assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
    636 }
    637 }
    638 else
    639 {
    640 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
    641 (*ownerdata)->filterpos = -2;
    642 }
    643
    644 *ownerfree = exprownerFree;
    645 *ownerprint = exprownerPrint;
    646 *ownerevalactivity = exprownerEvalactivity;
    647
    648 return SCIP_OKAY;
    649}
    650
    651/** creates a variable expression or retrieves from hashmap in conshdlr data */
    652static
    654 SCIP* scip, /**< SCIP data structure */
    655 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    656 SCIP_EXPR** expr, /**< pointer where to store expression */
    657 SCIP_VAR* var /**< variable to be stored */
    658 )
    659{
    660 assert(conshdlr != NULL);
    661 assert(expr != NULL);
    662 assert(var != NULL);
    663
    664 /* get variable expression representing the given variable if there is one already */
    665 *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
    666
    667 if( *expr == NULL )
    668 {
    669 /* create a new variable expression; this also captures the expression */
    670 SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
    671 assert(*expr != NULL);
    672 /* exprownerCreate should have added var->expr to var2expr */
    673 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
    674 }
    675 else
    676 {
    677 /* only capture already existing expr to get a consistent uses-count */
    678 SCIPcaptureExpr(*expr);
    679 }
    680
    681 return SCIP_OKAY;
    682}
    683
    684/* map var exprs to var-expr from var2expr hashmap */
    685static
    687{ /*lint --e{715}*/
    688 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
    689
    690 assert(sourcescip != NULL);
    691 assert(targetscip != NULL);
    692 assert(sourceexpr != NULL);
    693 assert(targetexpr != NULL);
    694 assert(*targetexpr == NULL);
    695 assert(mapexprdata != NULL);
    696
    697 /* do not provide map if not variable */
    698 if( !SCIPisExprVar(sourcescip, sourceexpr) )
    699 return SCIP_OKAY;
    700
    701 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
    702
    703 return SCIP_OKAY;
    704}
    705
    706/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
    707static
    709{ /*lint --e{715}*/
    710 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
    711 SCIP_VAR* var;
    712
    713 assert(sourcescip != NULL);
    714 assert(targetscip != NULL);
    715 assert(sourceexpr != NULL);
    716 assert(targetexpr != NULL);
    717 assert(*targetexpr == NULL);
    718 assert(mapexprdata != NULL);
    719
    720 /* do not provide map if not variable */
    721 if( !SCIPisExprVar(sourcescip, sourceexpr) )
    722 return SCIP_OKAY;
    723
    724 var = SCIPgetVarExprVar(sourceexpr);
    725 assert(var != NULL);
    726
    727 /* transform variable */
    728 SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
    729 assert(var != NULL);
    730
    731 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
    732
    733 return SCIP_OKAY;
    734}
    735
    736/** stores all variable expressions into a given constraint */
    737static
    739 SCIP* scip, /**< SCIP data structure */
    740 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    741 SCIP_CONSDATA* consdata /**< constraint data */
    742 )
    743{
    744 SCIP_CONSHDLRDATA* conshdlrdata;
    745 int varexprssize;
    746 int i;
    747
    748 assert(consdata != NULL);
    749
    750 /* skip if we have stored the variable expressions already */
    751 if( consdata->varexprs != NULL )
    752 return SCIP_OKAY;
    753
    754 assert(consdata->varexprs == NULL);
    755 assert(consdata->nvarexprs == 0);
    756
    757 /* get an upper bound on number of variable expressions */
    758 if( consdata->issimplified )
    759 {
    760 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
    761 * so we cannot have more variable expression than the number of active variables
    762 */
    763 varexprssize = SCIPgetNVars(scip);
    764 }
    765 else
    766 {
    767 SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
    768 }
    769
    770 /* create array to store all variable expressions */
    771 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
    772
    773 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
    774 assert(varexprssize >= consdata->nvarexprs);
    775
    776 /* shrink array if there are less variables in the expression than in the problem */
    777 if( varexprssize > consdata->nvarexprs )
    778 {
    779 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
    780 }
    781
    782 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    783 assert(conshdlrdata != NULL);
    784 assert(conshdlrdata->var2expr != NULL);
    785
    786 /* ensure that for every variable an entry exists in the var2expr hashmap
    787 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
    788 */
    789 for( i = 0; i < consdata->nvarexprs; ++i )
    790 {
    791 if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
    792 {
    793 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
    794 }
    795 }
    796
    797 return SCIP_OKAY;
    798}
    799
    800/** frees all variable expression stored in storeVarExprs() */
    801static
    803 SCIP* scip, /**< SCIP data structure */
    804 SCIP_CONSDATA* consdata /**< constraint data */
    805 )
    806{
    807 int i;
    808
    809 assert(consdata != NULL);
    810
    811 /* skip if we have stored the variable expressions already */
    812 if( consdata->varexprs == NULL )
    813 return SCIP_OKAY;
    814
    815 assert(consdata->varexprs != NULL);
    816 assert(consdata->nvarexprs >= 0);
    817 assert(!consdata->catchedevents);
    818
    819 /* release variable expressions */
    820 for( i = 0; i < consdata->nvarexprs; ++i )
    821 {
    822 assert(consdata->varexprs[i] != NULL);
    823 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
    824 assert(consdata->varexprs[i] == NULL);
    825 }
    826
    827 /* free variable expressions */
    828 SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
    829 consdata->varexprs = NULL;
    830 consdata->nvarexprs = 0;
    831
    832 return SCIP_OKAY;
    833}
    834
    835/** interval evaluation of variables as used in bound tightening
    836 *
    837 * Returns slightly relaxed local variable bounds of a variable as interval.
    838 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
    839 */
    840static
    841SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
    842{
    843 SCIP_INTERVAL interval;
    844 SCIP_CONSHDLRDATA* conshdlrdata;
    845 SCIP_Real lb;
    846 SCIP_Real ub;
    847
    848 assert(scip != NULL);
    849 assert(var != NULL);
    850
    851 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
    852 assert(conshdlrdata != NULL);
    853
    854 if( conshdlrdata->globalbounds )
    855 {
    856 lb = SCIPvarGetLbGlobal(var);
    857 ub = SCIPvarGetUbGlobal(var);
    858 }
    859 else
    860 {
    861 lb = SCIPvarGetLbLocal(var);
    862 ub = SCIPvarGetUbLocal(var);
    863 }
    864 assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
    865
    866 /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
    867 if( SCIPvarIsImpliedIntegral(var) )
    868 {
    869 lb = EPSROUND(lb, 0.0); /*lint !e835*/
    870 ub = EPSROUND(ub, 0.0); /*lint !e835*/
    871 }
    872
    873 /* integer variables should always have integral bounds in SCIP */
    874 assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
    875 assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
    876
    877 switch( conshdlrdata->varboundrelax )
    878 {
    879 case 'n' : /* no relaxation */
    880 break;
    881
    882 case 'a' : /* relax by absolute value */
    883 {
    884 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
    885 if( SCIPvarIsIntegral(var) )
    886 break;
    887
    888 if( !SCIPisInfinity(scip, -lb) )
    889 {
    890 /* reduce lb by epsilon, or to the next integer value, which ever is larger */
    891 SCIP_Real bnd = floor(lb);
    892 lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
    893 }
    894
    895 if( !SCIPisInfinity(scip, ub) )
    896 {
    897 /* increase ub by epsilon, or to the next integer value, which ever is smaller */
    898 SCIP_Real bnd = ceil(ub);
    899 ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
    900 }
    901
    902 break;
    903 }
    904
    905 case 'b' : /* relax always by absolute value */
    906 {
    907 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
    908 if( SCIPvarIsIntegral(var) )
    909 break;
    910
    911 if( !SCIPisInfinity(scip, -lb) )
    912 lb -= conshdlrdata->varboundrelaxamount;
    913
    914 if( !SCIPisInfinity(scip, ub) )
    915 ub += conshdlrdata->varboundrelaxamount;
    916
    917 break;
    918 }
    919
    920 case 'r' : /* relax by relative value */
    921 {
    922 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
    923 if( SCIPvarIsIntegral(var) )
    924 break;
    925
    926 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
    927 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
    928 * further, do not relax beyond next integer value
    929 */
    930 if( !SCIPisInfinity(scip, -lb) )
    931 {
    932 SCIP_Real bnd = floor(lb);
    933 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
    934 }
    935
    936 if( !SCIPisInfinity(scip, ub) )
    937 {
    938 SCIP_Real bnd = ceil(ub);
    939 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
    940 }
    941
    942 break;
    943 }
    944
    945 default :
    946 {
    947 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
    948 SCIPABORT();
    949 break;
    950 }
    951 }
    952
    953 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
    956 assert(lb <= ub);
    957
    958 SCIPintervalSetBounds(&interval, lb, ub);
    959
    960 return interval;
    961}
    962
    963/** compares two nonlinear constraints by its index
    964 *
    965 * Usable as compare operator in array sort functions.
    966 */
    967static
    968SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
    969{
    970 SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
    971 SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
    972
    973 assert(consdata1 != NULL);
    974 assert(consdata2 != NULL);
    975
    976 return consdata1->consindex - consdata2->consindex;
    977}
    978
    979/** processes variable fixing or bound change event */
    980static
    981SCIP_DECL_EVENTEXEC(processVarEvent)
    982{ /*lint --e{715}*/
    983 SCIP_EVENTTYPE eventtype;
    984 SCIP_EXPR* expr;
    985 SCIP_EXPR_OWNERDATA* ownerdata;
    986 SCIP_Bool boundtightened = FALSE;
    987
    988 eventtype = SCIPeventGetType(event);
    990
    991 assert(eventdata != NULL);
    992 expr = (SCIP_EXPR*) eventdata;
    993 assert(SCIPisExprVar(scip, expr));
    994
    995 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
    999
    1000 ownerdata = SCIPexprGetOwnerData(expr);
    1001 assert(ownerdata != NULL);
    1002 /* we only catch varevents for variables in constraints, so there should be constraints */
    1003 assert(ownerdata->nconss > 0);
    1004 assert(ownerdata->conss != NULL);
    1005
    1006 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
    1007 boundtightened = TRUE;
    1008
    1009 /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
    1010 * however, if the boundchange is smaller than epsilon, such an event will be omitted
    1011 * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
    1012 * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
    1013 * as a boundtightening (and usually it is, I would think)
    1014 */
    1015 if( eventtype & SCIP_EVENTTYPE_VARFIXED )
    1016 boundtightened = TRUE;
    1017
    1018 /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
    1019 * because we will round the bounds and no longer consider relaxing them
    1020 * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
    1021 * (mainly to avoid a failing assert, see github issue #70)
    1022 * usually, a change to implicit-integer would result in a boundchange on the variable as well, but not if the bound was already almost integral
    1023 */
    1025 && ( !EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) /*lint !e835*/
    1026 || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0) ) ) /*lint !e835*/
    1027 boundtightened = TRUE;
    1028
    1029 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
    1030 * - propagation can only find something new if a bound was tightened
    1031 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
    1032 * and we look at global changes (that is, we are not looking at boundchanges in probing)
    1033 */
    1034 if( boundtightened )
    1035 {
    1036 SCIP_CONSDATA* consdata;
    1037 int c;
    1038
    1039 for( c = 0; c < ownerdata->nconss; ++c )
    1040 {
    1041 assert(ownerdata->conss[c] != NULL);
    1042 consdata = SCIPconsGetData(ownerdata->conss[c]);
    1043
    1044 /* if bound tightening, then mark constraints to be propagated again
    1045 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
    1046 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
    1047 * the locks don't help since they are not available separately for each constraint
    1048 */
    1049 consdata->ispropagated = FALSE;
    1050 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
    1051
    1052 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
    1054 {
    1055 consdata->issimplified = FALSE;
    1056 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
    1057 }
    1058 }
    1059 }
    1060
    1061 /* update curboundstag, lastboundrelax, and expr activity */
    1062 if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
    1063 {
    1064 SCIP_CONSHDLRDATA* conshdlrdata;
    1065 SCIP_INTERVAL activity;
    1066
    1067 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    1068 assert(conshdlrdata != NULL);
    1069
    1070 /* increase tag on bounds */
    1071 ++conshdlrdata->curboundstag;
    1072 assert(conshdlrdata->curboundstag > 0);
    1073
    1074 /* remember also if we relaxed bounds now */
    1075 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
    1076 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
    1077
    1078 /* update the activity of the var-expr here immediately
    1079 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
    1080 */
    1081 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
    1082 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
    1083#ifdef DEBUG_PROP
    1084 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
    1085#endif
    1086 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
    1087 }
    1088
    1089 return SCIP_OKAY;
    1090}
    1091
    1092/** registers event handler to catch variable events on variable
    1093 *
    1094 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
    1095 * When an event occurs, all stored constraints are notified.
    1096 */
    1097static
    1099 SCIP* scip, /**< SCIP data structure */
    1100 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1101 SCIP_EXPR* expr, /**< variable expression */
    1102 SCIP_CONS* cons /**< nonlinear constraint */
    1103 )
    1104{
    1105 SCIP_EXPR_OWNERDATA* ownerdata;
    1106
    1107 assert(eventhdlr != NULL);
    1108 assert(expr != NULL);
    1109 assert(SCIPisExprVar(scip, expr));
    1110 assert(cons != NULL);
    1111
    1112 ownerdata = SCIPexprGetOwnerData(expr);
    1113 assert(ownerdata != NULL);
    1114
    1115#ifndef NDEBUG
    1116 /* assert that constraint does not double-catch variable */
    1117 {
    1118 int i;
    1119 for( i = 0; i < ownerdata->nconss; ++i )
    1120 assert(ownerdata->conss[i] != cons);
    1121 }
    1122#endif
    1123
    1124 /* append cons to ownerdata->conss */
    1125 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
    1126 ownerdata->conss[ownerdata->nconss++] = cons;
    1127 /* we're not capturing the constraint here to avoid circular references */
    1128
    1129 /* updated sorted flag */
    1130 if( ownerdata->nconss <= 1 )
    1131 ownerdata->consssorted = TRUE;
    1132 else if( ownerdata->consssorted )
    1133 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) < 0;
    1134
    1135 /* catch variable events, if not done so yet (first constraint) */
    1136 if( ownerdata->filterpos < 0 )
    1137 {
    1138 SCIP_EVENTTYPE eventtype;
    1139
    1140 assert(ownerdata->nconss == 1);
    1141
    1143
    1144 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
    1145 assert(ownerdata->filterpos >= 0);
    1146 }
    1147
    1148 return SCIP_OKAY;
    1149}
    1150
    1151/** catch variable events */
    1152static
    1154 SCIP* scip, /**< SCIP data structure */
    1155 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1156 SCIP_CONS* cons /**< constraint for which to catch bound change events */
    1157 )
    1158{
    1159 SCIP_CONSHDLRDATA* conshdlrdata;
    1160 SCIP_CONSDATA* consdata;
    1161 SCIP_EXPR* expr;
    1162 int i;
    1163
    1164 assert(eventhdlr != NULL);
    1165 assert(cons != NULL);
    1166
    1167 consdata = SCIPconsGetData(cons);
    1168 assert(consdata != NULL);
    1169 assert(consdata->varexprs != NULL);
    1170 assert(consdata->nvarexprs >= 0);
    1171
    1172 /* check if we have catched variable events already */
    1173 if( consdata->catchedevents )
    1174 return SCIP_OKAY;
    1175
    1176 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    1177 assert(conshdlrdata != NULL);
    1178#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
    1179 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
    1180#endif
    1181
    1182 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
    1183
    1184 for( i = 0; i < consdata->nvarexprs; ++i )
    1185 {
    1186 expr = consdata->varexprs[i];
    1187
    1188 assert(expr != NULL);
    1189 assert(SCIPisExprVar(scip, expr));
    1190
    1191 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
    1192
    1193 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
    1194 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
    1195 */
    1196 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
    1197 {
    1198 SCIP_INTERVAL activity;
    1199 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
    1200 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
    1201 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
    1202#ifdef DEBUG_PROP
    1203 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
    1204#endif
    1205 }
    1206 }
    1207
    1208 consdata->catchedevents = TRUE;
    1209
    1210 return SCIP_OKAY;
    1211}
    1212
    1213/** unregisters event handler to catch variable events on variable
    1214 *
    1215 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
    1216 * If this was the last constraint, then the event handler is unregistered for this variable.
    1217 */
    1218static
    1220 SCIP* scip, /**< SCIP data structure */
    1221 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1222 SCIP_EXPR* expr, /**< variable expression */
    1223 SCIP_CONS* cons /**< expr constraint */
    1224 )
    1225{
    1226 SCIP_EXPR_OWNERDATA* ownerdata;
    1227 int pos;
    1228
    1229 assert(eventhdlr != NULL);
    1230 assert(expr != NULL);
    1231 assert(SCIPisExprVar(scip, expr));
    1232 assert(cons != NULL);
    1233
    1234 ownerdata = SCIPexprGetOwnerData(expr);
    1235 assert(ownerdata != NULL);
    1236 assert(ownerdata->nconss > 0);
    1237
    1238 if( ownerdata->conss[ownerdata->nconss-1] == cons )
    1239 {
    1240 pos = ownerdata->nconss-1;
    1241 }
    1242 else
    1243 {
    1244 if( !ownerdata->consssorted )
    1245 {
    1246 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
    1247 ownerdata->consssorted = TRUE;
    1248 }
    1249
    1250 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
    1251 {
    1252 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
    1253 return SCIP_ERROR;
    1254 }
    1255 assert(pos >= 0 && pos < ownerdata->nconss);
    1256 }
    1257 assert(ownerdata->conss[pos] == cons);
    1258
    1259 /* move last constraint into position of removed constraint */
    1260 if( pos < ownerdata->nconss-1 )
    1261 {
    1262 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
    1263 ownerdata->consssorted = FALSE;
    1264 }
    1265 --ownerdata->nconss;
    1266
    1267 /* drop variable events if that was the last constraint */
    1268 if( ownerdata->nconss == 0 )
    1269 {
    1270 SCIP_EVENTTYPE eventtype;
    1271
    1272 assert(ownerdata->filterpos >= 0);
    1273
    1275
    1276 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
    1277 ownerdata->filterpos = -1;
    1278 }
    1279
    1280 return SCIP_OKAY;
    1281}
    1282
    1283/** drop variable events */
    1284static
    1286 SCIP* scip, /**< SCIP data structure */
    1287 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1288 SCIP_CONS* cons /**< constraint for which to drop bound change events */
    1289 )
    1290{
    1291 SCIP_CONSDATA* consdata;
    1292 int i;
    1293
    1294 assert(eventhdlr != NULL);
    1295 assert(cons != NULL);
    1296
    1297 consdata = SCIPconsGetData(cons);
    1298 assert(consdata != NULL);
    1299
    1300 /* check if we have catched variable events already */
    1301 if( !consdata->catchedevents )
    1302 return SCIP_OKAY;
    1303
    1304 assert(consdata->varexprs != NULL);
    1305 assert(consdata->nvarexprs >= 0);
    1306
    1307 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
    1308
    1309 for( i = consdata->nvarexprs - 1; i >= 0; --i )
    1310 {
    1311 assert(consdata->varexprs[i] != NULL);
    1312
    1313 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
    1314 }
    1315
    1316 consdata->catchedevents = FALSE;
    1317
    1318 return SCIP_OKAY;
    1319}
    1320
    1321/** creates and captures a nonlinear constraint
    1322 *
    1323 * @attention Use copyexpr=FALSE only if expr is already "owned" by conshdlr, that is, if expressions were created with exprownerCreate() and ownerdata passed in the last two arguments
    1324 */
    1325static
    1327 SCIP* scip, /**< SCIP data structure */
    1328 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    1329 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    1330 const char* name, /**< name of constraint */
    1331 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
    1332 SCIP_Real lhs, /**< left hand side of constraint */
    1333 SCIP_Real rhs, /**< right hand side of constraint */
    1334 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
    1335 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    1336 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    1337 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    1338 * Usually set to TRUE. */
    1339 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    1340 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    1341 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    1342 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    1343 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    1344 * Usually set to TRUE. */
    1345 SCIP_Bool local, /**< is constraint only valid locally?
    1346 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    1347 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    1348 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    1349 * adds coefficients to this constraint. */
    1350 SCIP_Bool dynamic, /**< is constraint subject to aging?
    1351 * Usually set to FALSE. Set to TRUE for own cuts which
    1352 * are separated as constraints. */
    1353 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
    1354 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    1355 )
    1356{
    1357 SCIP_CONSHDLRDATA* conshdlrdata;
    1358 SCIP_CONSDATA* consdata;
    1359
    1360 assert(conshdlr != NULL);
    1361 assert(expr != NULL);
    1362
    1363 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1364 assert(conshdlrdata != NULL);
    1365
    1366 if( local && SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
    1367 {
    1368 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
    1369 return SCIP_INVALIDCALL;
    1370 }
    1371
    1372 /* TODO we should allow for non-initial nonlinear constraints */
    1373 if( !initial )
    1374 {
    1375 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
    1376 return SCIP_INVALIDCALL;
    1377 }
    1378
    1379 if( isnan(lhs) || isnan(rhs) )
    1380 {
    1381 SCIPerrorMessage("%s hand side of nonlinear constraint <%s> is nan\n",
    1382 isnan(lhs) ? "left" : "right", name);
    1383 return SCIP_INVALIDDATA;
    1384 }
    1385
    1386 /* create constraint data */
    1388
    1389 if( copyexpr )
    1390 {
    1391 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
    1392 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    1393 }
    1394 else
    1395 {
    1396 consdata->expr = expr;
    1397 SCIPcaptureExpr(consdata->expr);
    1398 }
    1399 consdata->lhs = lhs;
    1400 consdata->rhs = rhs;
    1401 consdata->consindex = conshdlrdata->lastconsindex++;
    1402 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
    1403
    1404 /* create constraint */
    1405 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    1406 local, modifiable, dynamic, removable, FALSE) );
    1407
    1408 return SCIP_OKAY;
    1409}
    1410
    1411/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
    1412 *
    1413 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
    1414 * Assume that f(x) is associated with auxiliary variable z.
    1415 *
    1416 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
    1417 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
    1418 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
    1419 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
    1420 *
    1421 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
    1422 */
    1423static
    1425 SCIP* scip, /**< SCIP data structure */
    1426 SCIP_EXPR* expr, /**< expression */
    1427 SCIP_SOL* sol, /**< solution that has been evaluated */
    1428 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
    1429 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
    1430 )
    1431{
    1432 SCIP_EXPR_OWNERDATA* ownerdata;
    1433 SCIP_Real auxvarvalue;
    1434
    1435 assert(expr != NULL);
    1436
    1437 ownerdata = SCIPexprGetOwnerData(expr);
    1438 assert(ownerdata != NULL);
    1439 assert(ownerdata->auxvar != NULL);
    1440
    1441 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
    1442 {
    1443 if( violunder != NULL )
    1444 *violunder = TRUE;
    1445 if( violover != NULL )
    1446 *violover = TRUE;
    1447 return SCIPinfinity(scip);
    1448 }
    1449
    1450 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
    1451
    1452 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
    1453 {
    1454 if( violunder != NULL )
    1455 *violunder = FALSE;
    1456 if( violover != NULL )
    1457 *violover = TRUE;
    1458 return auxvarvalue - SCIPexprGetEvalValue(expr);
    1459 }
    1460
    1461 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
    1462 {
    1463 if( violunder != NULL )
    1464 *violunder = TRUE;
    1465 if( violover != NULL )
    1466 *violover = FALSE;
    1467 return SCIPexprGetEvalValue(expr) - auxvarvalue;
    1468 }
    1469
    1470 if( violunder != NULL )
    1471 *violunder = FALSE;
    1472 if( violover != NULL )
    1473 *violover = FALSE;
    1474 return 0.0;
    1475}
    1476
    1477/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
    1478 *
    1479 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
    1480 * Assume that f(w) is associated with auxiliary variable z.
    1481 *
    1482 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
    1483 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
    1484 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
    1485 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
    1486 *
    1487 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
    1488 */
    1489static
    1491 SCIP* scip, /**< SCIP data structure */
    1492 SCIP_EXPR* expr, /**< expression */
    1493 SCIP_Real auxvalue, /**< value of f(w) */
    1494 SCIP_SOL* sol, /**< solution that has been evaluated */
    1495 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
    1496 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
    1497 )
    1498{
    1499 SCIP_EXPR_OWNERDATA* ownerdata;
    1500 SCIP_Real auxvarvalue;
    1501
    1502 assert(expr != NULL);
    1503
    1504 ownerdata = SCIPexprGetOwnerData(expr);
    1505 assert(ownerdata != NULL);
    1506 assert(ownerdata->auxvar != NULL);
    1507
    1508 if( auxvalue == SCIP_INVALID )
    1509 {
    1510 if( violunder != NULL )
    1511 *violunder = TRUE;
    1512 if( violover != NULL )
    1513 *violover = TRUE;
    1514 return SCIPinfinity(scip);
    1515 }
    1516
    1517 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
    1518
    1519 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
    1520 {
    1521 if( violunder != NULL )
    1522 *violunder = FALSE;
    1523 if( violover != NULL )
    1524 *violover = TRUE;
    1525 return auxvarvalue - auxvalue;
    1526 }
    1527
    1528 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
    1529 {
    1530 if( violunder != NULL )
    1531 *violunder = TRUE;
    1532 if( violover != NULL )
    1533 *violover = FALSE;
    1534 return auxvalue - auxvarvalue;
    1535 }
    1536
    1537 if( violunder != NULL )
    1538 *violunder = FALSE;
    1539 if( violover != NULL )
    1540 *violover = FALSE;
    1541
    1542 return 0.0;
    1543}
    1544
    1545/** computes violation of a constraint */
    1546static
    1548 SCIP* scip, /**< SCIP data structure */
    1549 SCIP_CONS* cons, /**< constraint */
    1550 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
    1551 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
    1552 )
    1553{
    1554 SCIP_CONSDATA* consdata;
    1555 SCIP_Real activity;
    1556
    1557 assert(scip != NULL);
    1558 assert(cons != NULL);
    1559
    1560 consdata = SCIPconsGetData(cons);
    1561 assert(consdata != NULL);
    1562
    1563 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
    1564 activity = SCIPexprGetEvalValue(consdata->expr);
    1565
    1566 /* consider constraint as violated if it is undefined in the current point */
    1567 if( activity == SCIP_INVALID )
    1568 {
    1569 consdata->lhsviol = SCIPinfinity(scip);
    1570 consdata->rhsviol = SCIPinfinity(scip);
    1571 return SCIP_OKAY;
    1572 }
    1573
    1574 /* compute violations */
    1575 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
    1576 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
    1577
    1578 return SCIP_OKAY;
    1579}
    1580
    1581/** returns absolute violation of a constraint
    1582 *
    1583 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
    1584 */
    1585static
    1587 SCIP_CONS* cons /**< constraint */
    1588 )
    1589{
    1590 SCIP_CONSDATA* consdata;
    1591
    1592 assert(cons != NULL);
    1593
    1594 consdata = SCIPconsGetData(cons);
    1595 assert(consdata != NULL);
    1596
    1597 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
    1598}
    1599
    1600/** computes relative violation of a constraint
    1601 *
    1602 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
    1603 */
    1604static
    1606 SCIP* scip, /**< SCIP data structure */
    1607 SCIP_CONS* cons, /**< constraint */
    1608 SCIP_Real* viol, /**< buffer to store violation */
    1609 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
    1610 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
    1611 )
    1612{
    1613 SCIP_CONSHDLR* conshdlr;
    1614 SCIP_CONSHDLRDATA* conshdlrdata;
    1615 SCIP_CONSDATA* consdata;
    1616 SCIP_Real scale;
    1617
    1618 assert(cons != NULL);
    1619 assert(viol != NULL);
    1620
    1621 conshdlr = SCIPconsGetHdlr(cons);
    1622 assert(conshdlr != NULL);
    1623
    1624 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1625 assert(conshdlrdata != NULL);
    1626
    1627 *viol = getConsAbsViolation(cons);
    1628
    1629 if( conshdlrdata->violscale == 'n' )
    1630 return SCIP_OKAY;
    1631
    1632 if( SCIPisInfinity(scip, *viol) )
    1633 return SCIP_OKAY;
    1634
    1635 consdata = SCIPconsGetData(cons);
    1636 assert(consdata != NULL);
    1637
    1638 if( conshdlrdata->violscale == 'a' )
    1639 {
    1640 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
    1641
    1642 /* consider value of side that is violated for scaling, too */
    1643 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
    1644 {
    1645 assert(!SCIPisInfinity(scip, -consdata->lhs));
    1646 scale = REALABS(consdata->lhs);
    1647 }
    1648 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
    1649 {
    1650 assert(!SCIPisInfinity(scip, consdata->rhs));
    1651 scale = REALABS(consdata->rhs);
    1652 }
    1653
    1654 *viol /= scale;
    1655 return SCIP_OKAY;
    1656 }
    1657
    1658 /* if not 'n' or 'a', then it has to be 'g' at the moment */
    1659 assert(conshdlrdata->violscale == 'g');
    1660 if( soltag == 0L || consdata->gradnormsoltag != soltag )
    1661 {
    1662 /* we need the varexprs to conveniently access the gradient */
    1663 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    1664
    1665 /* update cached value of norm of gradient */
    1666 consdata->gradnorm = 0.0;
    1667
    1668 /* compute gradient */
    1669 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
    1670
    1671 /* gradient evaluation error -> no scaling */
    1672 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
    1673 {
    1674 int i;
    1675 for( i = 0; i < consdata->nvarexprs; ++i )
    1676 {
    1677 SCIP_Real deriv;
    1678
    1679 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
    1680 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
    1681 if( deriv == SCIP_INVALID )
    1682 {
    1683 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
    1684 consdata->gradnorm = 0.0;
    1685 break;
    1686 }
    1687
    1688 consdata->gradnorm += deriv*deriv;
    1689 }
    1690 }
    1691 consdata->gradnorm = sqrt(consdata->gradnorm);
    1692 consdata->gradnormsoltag = soltag;
    1693 }
    1694
    1695 *viol /= MAX(1.0, consdata->gradnorm);
    1696
    1697 return SCIP_OKAY;
    1698}
    1699
    1700/** returns whether constraint is currently violated
    1701 *
    1702 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
    1703 */
    1704static
    1706 SCIP* scip, /**< SCIP data structure */
    1707 SCIP_CONS* cons /**< constraint */
    1708 )
    1709{
    1710 return getConsAbsViolation(cons) > SCIPfeastol(scip);
    1711}
    1712
    1713/** checks for a linear variable that can be increased or decreased without harming feasibility */
    1714static
    1716 SCIP* scip, /**< SCIP data structure */
    1717 SCIP_CONS* cons /**< constraint */
    1718 )
    1719{
    1720 SCIP_CONSDATA* consdata;
    1721 int poslock;
    1722 int neglock;
    1723 int i;
    1724
    1725 assert(cons != NULL);
    1726
    1727 consdata = SCIPconsGetData(cons);
    1728 assert(consdata != NULL);
    1729
    1730 consdata->linvarincr = NULL;
    1731 consdata->linvardecr = NULL;
    1732 consdata->linvarincrcoef = 0.0;
    1733 consdata->linvardecrcoef = 0.0;
    1734
    1735 /* root expression is not a sum -> no unlocked linear variable available */
    1736 if( !SCIPisExprSum(scip, consdata->expr) )
    1737 return;
    1738
    1739 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
    1740 {
    1741 SCIP_EXPR* child;
    1742
    1743 child = SCIPexprGetChildren(consdata->expr)[i];
    1744 assert(child != NULL);
    1745
    1746 /* check whether the child is a variable expression */
    1747 if( SCIPisExprVar(scip, child) )
    1748 {
    1749 SCIP_VAR* var = SCIPgetVarExprVar(child);
    1750 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
    1751
    1752 if( coef > 0.0 )
    1753 {
    1754 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
    1755 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
    1756 }
    1757 else
    1758 {
    1759 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
    1760 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
    1761 }
    1763
    1764 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
    1765 {
    1766 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
    1767 * if we have already one candidate, then take the one where the loss in the objective function is less
    1768 */
    1769 if( (consdata->linvardecr == NULL) ||
    1770 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
    1771 {
    1772 consdata->linvardecr = var;
    1773 consdata->linvardecrcoef = coef;
    1774 }
    1775 }
    1776
    1777 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
    1778 {
    1779 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
    1780 * if we have already one candidate, then take the one where the loss in the objective function is less
    1781 */
    1782 if( (consdata->linvarincr == NULL) ||
    1783 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
    1784 {
    1785 consdata->linvarincr = var;
    1786 consdata->linvarincrcoef = coef;
    1787 }
    1788 }
    1789 }
    1790 }
    1791
    1792 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
    1793 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
    1794
    1795 if( consdata->linvarincr != NULL )
    1796 {
    1797 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
    1798 }
    1799 if( consdata->linvardecr != NULL )
    1800 {
    1801 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
    1802 }
    1803}
    1804
    1805/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
    1806 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
    1807 *
    1808 * The method assumes that this is always possible and that not all constraints are feasible already.
    1809 */
    1810static
    1812 SCIP* scip, /**< SCIP data structure */
    1813 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    1814 SCIP_CONS** conss, /**< constraints to process */
    1815 int nconss, /**< number of constraints */
    1816 SCIP_SOL* sol, /**< solution to process */
    1817 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
    1818 )
    1819{
    1820 SCIP_CONSHDLRDATA* conshdlrdata;
    1821 SCIP_SOL* newsol;
    1822 int c;
    1823
    1824 assert(scip != NULL);
    1825 assert(conshdlr != NULL);
    1826 assert(conss != NULL || nconss == 0);
    1827 assert(success != NULL);
    1828
    1829 *success = FALSE;
    1830
    1831 /* don't propose new solutions if not in presolve or solving */
    1833 return SCIP_OKAY;
    1834
    1835 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1836 assert(conshdlrdata != NULL);
    1837
    1838 if( sol != NULL )
    1839 {
    1840 SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
    1841 }
    1842 else
    1843 {
    1844 SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
    1845 }
    1846 SCIP_CALL( SCIPunlinkSol(scip, newsol) );
    1847 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
    1848 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
    1849
    1850 for( c = 0; c < nconss; ++c )
    1851 {
    1852 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
    1853 SCIP_Real viol = 0.0;
    1854 SCIP_Real delta;
    1855 SCIP_Real gap;
    1856
    1857 assert(consdata != NULL);
    1858
    1859 /* get absolute violation and sign */
    1860 if( consdata->lhsviol > SCIPfeastol(scip) )
    1861 viol = consdata->lhsviol; /* lhs - activity */
    1862 else if( consdata->rhsviol > SCIPfeastol(scip) )
    1863 viol = -consdata->rhsviol; /* rhs - activity */
    1864 else
    1865 continue; /* constraint is satisfied */
    1866
    1867 if( consdata->linvarincr != NULL &&
    1868 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
    1869 {
    1870 SCIP_VAR* var = consdata->linvarincr;
    1871
    1872 /* compute how much we would like to increase var */
    1873 delta = viol / consdata->linvarincrcoef;
    1874 assert(delta > 0.0);
    1875
    1876 /* if var has an upper bound, may need to reduce delta */
    1878 {
    1879 gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
    1880 delta = MIN(MAX(0.0, gap), delta);
    1881 }
    1882 if( SCIPisPositive(scip, delta) )
    1883 {
    1884 /* if variable is integral, round delta up so that it will still have an integer value */
    1885 if( SCIPvarIsIntegral(var) )
    1886 delta = SCIPceil(scip, delta);
    1887
    1888 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
    1889 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
    1890 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
    1891
    1892 /* adjust constraint violation, if satisfied go on to next constraint */
    1893 viol -= consdata->linvarincrcoef * delta;
    1894 if( SCIPisZero(scip, viol) )
    1895 continue;
    1896 }
    1897 }
    1898
    1899 assert(viol != 0.0);
    1900 if( consdata->linvardecr != NULL &&
    1901 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
    1902 {
    1903 SCIP_VAR* var = consdata->linvardecr;
    1904
    1905 /* compute how much we would like to decrease var */
    1906 delta = viol / consdata->linvardecrcoef;
    1907 assert(delta < 0.0);
    1908
    1909 /* if var has a lower bound, may need to reduce delta */
    1911 {
    1912 gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
    1913 delta = MAX(MIN(0.0, gap), delta);
    1914 }
    1915 if( SCIPisNegative(scip, delta) )
    1916 {
    1917 /* if variable is integral, round delta down so that it will still have an integer value */
    1918 if( SCIPvarIsIntegral(var) )
    1919 delta = SCIPfloor(scip, delta);
    1920 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
    1921 /*lint --e{613} */
    1922 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
    1923 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
    1924
    1925 /* adjust constraint violation, if satisfied go on to next constraint */
    1926 viol -= consdata->linvardecrcoef * delta;
    1927 if( SCIPisZero(scip, viol) )
    1928 continue;
    1929 }
    1930 }
    1931
    1932 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
    1933 break;
    1934 }
    1935
    1936 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
    1937 * then pass it to the trysol heuristic
    1938 */
    1940 {
    1941 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
    1942
    1943 assert(conshdlrdata->trysolheur != NULL);
    1944 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
    1945
    1946 *success = TRUE;
    1947 }
    1948
    1949 SCIP_CALL( SCIPfreeSol(scip, &newsol) );
    1950
    1951 return SCIP_OKAY;
    1952}
    1953
    1954/** notify nonlinear handlers to add linearization in new solution that has been found
    1955 *
    1956 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
    1957 *
    1958 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
    1959 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
    1960 * cut that is valid and supporting in the given solution.
    1961 * For example, for convex constraints, we achieve this by linearizing.
    1962 * For SOC, we also linearize, but on a a convex reformulation.
    1963 *
    1964 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
    1965 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
    1966 */
    1967static
    1969 SCIP* scip, /**< SCIP data structure */
    1970 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    1971 SCIP_CONS** conss, /**< constraints */
    1972 int nconss, /**< number of constraints */
    1973 SCIP_SOL* sol, /**< reference point where to estimate */
    1974 SCIP_Bool solisbest /**< whether solution is best */
    1975 )
    1976{
    1977 SCIP_CONSDATA* consdata;
    1978 SCIP_Longint soltag;
    1979 SCIP_EXPRITER* it;
    1980 SCIP_EXPR* expr;
    1981 int c, e;
    1982
    1983 assert(scip != NULL);
    1984 assert(conshdlr != NULL);
    1985 assert(conss != NULL || nconss == 0);
    1986
    1987 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
    1988
    1989 /* TODO probably we just evaluated all expressions when checking the sol before it was added
    1990 * would be nice to recognize this and skip reevaluating
    1991 */
    1992 soltag = SCIPgetExprNewSoltag(scip);
    1993
    1997
    1998 for( c = 0; c < nconss; ++c )
    1999 {
    2000 /* skip constraints that are not enabled or deleted or have separation disabled */
    2001 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
    2002 continue;
    2003 assert(SCIPconsIsActive(conss[c]));
    2004
    2005 consdata = SCIPconsGetData(conss[c]);
    2006 assert(consdata != NULL);
    2007
    2008 ENFOLOG(
    2009 {
    2010 int i;
    2011 SCIPinfoMessage(scip, enfologfile, " constraint ");
    2012 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
    2013 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
    2014 for( i = 0; i < consdata->nvarexprs; ++i )
    2015 {
    2016 SCIP_VAR* var;
    2017 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    2018 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
    2019 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
    2020 }
    2021 })
    2022
    2023 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
    2024 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
    2025
    2026 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    2027 {
    2028 SCIP_EXPR_OWNERDATA* ownerdata;
    2029
    2030 ownerdata = SCIPexprGetOwnerData(expr);
    2031 assert(ownerdata != NULL);
    2032
    2033 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
    2034 assert(SCIPexprGetEvalTag(expr) == soltag);
    2035 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
    2036 if( ownerdata->auxvar != NULL )
    2037 {
    2038 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
    2039 }
    2040
    2041 /* let nonlinear handler generate cuts by calling the sollinearize callback */
    2042 for( e = 0; e < ownerdata->nenfos; ++e )
    2043 {
    2044 /* call sollinearize callback, if implemented by nlhdlr */
    2045 SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
    2046 ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
    2047 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
    2048 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
    2049 }
    2050 }
    2051 }
    2052
    2053 SCIPfreeExpriter(&it);
    2054
    2055 return SCIP_OKAY;
    2056}
    2057
    2058/** processes the event that a new primal solution has been found */
    2059static
    2060SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
    2061{
    2062 SCIP_CONSHDLR* conshdlr;
    2063 SCIP_CONSHDLRDATA* conshdlrdata;
    2064 SCIP_SOL* sol;
    2065
    2066 assert(scip != NULL);
    2067 assert(event != NULL);
    2068 assert(eventdata != NULL);
    2069 assert(eventhdlr != NULL);
    2071
    2072 conshdlr = (SCIP_CONSHDLR*)eventdata;
    2073
    2074 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
    2075 return SCIP_OKAY;
    2076
    2077 sol = SCIPeventGetSol(event);
    2078 assert(sol != NULL);
    2079
    2080 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2081 assert(conshdlrdata != NULL);
    2082
    2083 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
    2084 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
    2085 * from the tree, but postprocessed via proposeFeasibleSolution
    2086 */
    2087 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
    2088 return SCIP_OKAY;
    2089
    2090 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
    2091
    2093
    2094 return SCIP_OKAY;
    2095}
    2096
    2097/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
    2098 *
    2099 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
    2100 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
    2101 *
    2102 * Nothing will happen if SCIP is not in presolve or solve.
    2103 */
    2104static
    2106 SCIP* scip, /**< SCIP data structure */
    2107 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2108 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
    2109 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
    2110 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
    2111 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
    2112 )
    2113{
    2114 SCIP_VAR* var;
    2115 SCIP_Bool tightenedlb;
    2116 SCIP_Bool tightenedub;
    2117 SCIP_Bool force;
    2118
    2119 assert(scip != NULL);
    2120 assert(conshdlr != NULL);
    2121 assert(expr != NULL);
    2122 assert(cutoff != NULL);
    2123
    2124 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
    2126
    2127 *cutoff = FALSE;
    2128
    2129 var = SCIPgetExprAuxVarNonlinear(expr);
    2130 if( var == NULL )
    2131 return SCIP_OKAY;
    2132
    2133 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
    2134 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
    2135
    2136 /* try to tighten lower bound of (auxiliary) variable */
    2137 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
    2138 if( tightenedlb )
    2139 {
    2140 if( ntightenings != NULL )
    2141 ++*ntightenings;
    2142 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
    2143 }
    2144 if( *cutoff )
    2145 {
    2146 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
    2147 return SCIP_OKAY;
    2148 }
    2149
    2150 /* try to tighten upper bound of (auxiliary) variable */
    2151 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
    2152 if( tightenedub )
    2153 {
    2154 if( ntightenings != NULL )
    2155 ++*ntightenings;
    2156 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
    2157 }
    2158 if( *cutoff )
    2159 {
    2160 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
    2161 return SCIP_OKAY;
    2162 }
    2163
    2164 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
    2165 * that seems unnecessary and we could easily undo this here, e.g.,
    2166 * if( tightenedlb ) expr->activity.inf = bounds.inf
    2167 */
    2168
    2169 return SCIP_OKAY;
    2170}
    2171
    2172/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
    2173 * and tries to tighten the bounds of the auxiliary variables accordingly
    2174 */
    2175static
    2177 SCIP* scip, /**< SCIP data structure */
    2178 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2179 SCIP_EXPR* rootexpr, /**< expression */
    2180 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
    2181 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
    2182 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
    2183 )
    2184{
    2185 SCIP_EXPRITER* it;
    2186 SCIP_EXPR* expr;
    2187 SCIP_EXPR_OWNERDATA* ownerdata;
    2188 SCIP_CONSHDLRDATA* conshdlrdata;
    2189
    2190 assert(scip != NULL);
    2191 assert(rootexpr != NULL);
    2192
    2193 if( infeasible != NULL )
    2194 *infeasible = FALSE;
    2195 if( ntightenings != NULL )
    2196 *ntightenings = 0;
    2197
    2198 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2199 assert(conshdlrdata != NULL);
    2200
    2201 /* if value is valid and empty, then we cannot improve, so do nothing */
    2202 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
    2203 {
    2204 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
    2205
    2206 if( infeasible != NULL )
    2207 *infeasible = TRUE;
    2208
    2209 /* just update tag to curboundstag */
    2210 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
    2211
    2212 return SCIP_OKAY;
    2213 }
    2214
    2215 /* if value is up-to-date, then nothing to do */
    2216 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
    2217 {
    2218 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
    2219
    2220 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
    2221
    2222 return SCIP_OKAY;
    2223 }
    2224
    2225 ownerdata = SCIPexprGetOwnerData(rootexpr);
    2226 assert(ownerdata != NULL);
    2227
    2228 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
    2229 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
    2230 * during detect, we are in some in-between state where we may want to eval activity
    2231 * on exprs that we did not notify about their activity usage
    2232 */
    2233 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
    2234 {
    2235#ifdef DEBUG_PROP
    2236 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
    2237#endif
    2238 SCIPABORT();
    2239 return SCIP_OKAY;
    2240 }
    2241
    2245
    2246 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
    2247 {
    2248 switch( SCIPexpriterGetStageDFS(it) )
    2249 {
    2251 {
    2252 /* skip child if it has been evaluated already */
    2253 SCIP_EXPR* child;
    2254
    2255 child = SCIPexpriterGetChildExprDFS(it);
    2256 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
    2257 {
    2259 *infeasible = TRUE;
    2260
    2261 expr = SCIPexpriterSkipDFS(it);
    2262 continue;
    2263 }
    2264
    2265 break;
    2266 }
    2267
    2269 {
    2270 SCIP_INTERVAL activity;
    2271
    2272 /* we should not have entered this expression if its activity was already up to date */
    2273 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
    2274
    2275 ownerdata = SCIPexprGetOwnerData(expr);
    2276 assert(ownerdata != NULL);
    2277
    2278 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
    2279 * so we can assume that the activity is up to date for all these variables
    2280 * UNLESS we changed the method used to evaluate activity of variable expressions
    2281 * or we currently use global bounds (varevents are catched for local bound changes only)
    2282 */
    2283 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
    2284 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
    2285 {
    2286#ifndef NDEBUG
    2287 SCIP_INTERVAL exprhdlrinterval;
    2288
    2289 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
    2290 assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
    2291 assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
    2292#endif
    2293#ifdef DEBUG_PROP
    2294 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
    2295#endif
    2296 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
    2297
    2298 break;
    2299 }
    2300
    2301 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
    2302 {
    2303 /* start with entire activity if current one is invalid */
    2305 }
    2307 {
    2308 /* If already empty, then don't try to compute even better activity.
    2309 * If cons_nonlinear were alone, then we should have noted that we are infeasible
    2310 * so an assert(infeasible == NULL || *infeasible) should work here.
    2311 * However, after reporting a cutoff due to expr->activity being empty,
    2312 * SCIP may wander to a different node and call propagation again.
    2313 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
    2314 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
    2315 * we will still have expr->activity being empty, but will have forgotten
    2316 * that we found infeasibility here before (!2221#note_134120).
    2317 * Therefore we just set *infeasibility=TRUE here and stop.
    2318 */
    2319 if( infeasible != NULL )
    2320 *infeasible = TRUE;
    2321 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
    2322 break;
    2323 }
    2324 else
    2325 {
    2326 /* start with current activity, since it is valid */
    2327 activity = SCIPexprGetActivity(expr);
    2328 }
    2329
    2330 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
    2331 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
    2332 {
    2333#ifdef DEBUG_PROP
    2334 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
    2335#endif
    2336 break;
    2337 }
    2338
    2339#ifdef DEBUG_PROP
    2340 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
    2341 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    2342 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
    2343#endif
    2344
    2345 /* run interval eval of nonlinear handlers or expression handler */
    2346 if( ownerdata->nenfos > 0 )
    2347 {
    2348 SCIP_NLHDLR* nlhdlr;
    2349 SCIP_INTERVAL nlhdlrinterval;
    2350 int e;
    2351
    2352 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
    2353 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
    2354 {
    2355 /* skip nlhdlr if it does not want to participate in activity computation */
    2356 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
    2357 continue;
    2358
    2359 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    2360 assert(nlhdlr != NULL);
    2361
    2362 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
    2363 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
    2364 continue;
    2365
    2366 /* let nlhdlr evaluate current expression */
    2367 nlhdlrinterval = activity;
    2368 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
    2369 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
    2370#ifdef DEBUG_PROP
    2371 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
    2372#endif
    2373
    2374 /* update activity by intersecting with computed activity */
    2375 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
    2376#ifdef DEBUG_PROP
    2377 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
    2378#endif
    2379 }
    2380 }
    2381 else
    2382 {
    2383 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
    2384 SCIP_INTERVAL exprhdlrinterval = activity;
    2385 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
    2386#ifdef DEBUG_PROP
    2387 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
    2388#endif
    2389
    2390 /* update expr->activity by intersecting with computed activity */
    2391 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
    2392#ifdef DEBUG_PROP
    2393 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
    2394#endif
    2395 }
    2396
    2397 /* if expression is integral, then we try to tighten the interval bounds a bit
    2398 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
    2399 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
    2400 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
    2401 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
    2402 * (constants should be ok, too)
    2403 */
    2404 if( SCIPexprIsIntegral(expr) &&
    2405 conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
    2406 {
    2407 if( activity.inf > -SCIP_INTERVAL_INFINITY )
    2408 activity.inf = SCIPceil(scip, activity.inf);
    2409 if( activity.sup < SCIP_INTERVAL_INFINITY )
    2410 activity.sup = SCIPfloor(scip, activity.sup);
    2411#ifdef DEBUG_PROP
    2412 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
    2413#endif
    2414 }
    2415
    2416 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
    2417 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
    2418 */
    2419 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
    2420 {
    2421 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
    2422 SCIPintervalSetEmpty(&activity);
    2423 }
    2424
    2425 /* now finally store activity in expr */
    2426 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
    2427
    2429 {
    2430 if( infeasible != NULL )
    2431 *infeasible = TRUE;
    2432 }
    2433 else if( tightenauxvars && ownerdata->auxvar != NULL )
    2434 {
    2435 SCIP_Bool tighteninfeasible;
    2436
    2437 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
    2438 if( tighteninfeasible )
    2439 {
    2440 if( infeasible != NULL )
    2441 *infeasible = TRUE;
    2442 SCIPintervalSetEmpty(&activity);
    2443 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
    2444 }
    2445 }
    2446
    2447 break;
    2448 }
    2449
    2450 default:
    2451 /* you should never be here */
    2452 SCIPerrorMessage("unexpected iterator stage\n");
    2453 SCIPABORT();
    2454 break;
    2455 }
    2456
    2457 expr = SCIPexpriterGetNext(it);
    2458 }
    2459
    2460 SCIPfreeExpriter(&it);
    2461
    2462 return SCIP_OKAY;
    2463}
    2464
    2465/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
    2466 *
    2467 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
    2468 *
    2469 * If `subsetsufficient` is FALSE, then we require
    2470 * - a change from an unbounded interval to a bounded one, or
    2471 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
    2472 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
    2473 */
    2474static
    2476 SCIP* scip, /**< SCIP data structure */
    2477 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
    2478 SCIP_INTERVAL newinterval, /**< new interval */
    2479 SCIP_INTERVAL oldinterval /**< old interval */
    2480 )
    2481{
    2482 assert(scip != NULL);
    2483 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
    2484 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
    2485
    2486 if( subsetsufficient )
    2487 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
    2488 return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
    2489
    2490 /* check whether lower bound of interval becomes finite */
    2491 if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
    2492 return TRUE;
    2493
    2494 /* check whether upper bound of interval becomes finite */
    2495 if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
    2496 return TRUE;
    2497
    2498 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
    2499 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
    2500 return TRUE;
    2501
    2502 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
    2503 if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
    2504 return TRUE;
    2505
    2506 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
    2507 if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
    2508 return TRUE;
    2509
    2510 return FALSE;
    2511}
    2512
    2513/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
    2514 *
    2515 * The expression will be traversed in breadth first search by using this queue.
    2516 *
    2517 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
    2518 * forwardPropExpr() before calling this function.
    2519 *
    2520 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
    2521 */
    2522static
    2524 SCIP* scip, /**< SCIP data structure */
    2525 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2526 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
    2527 int* ntightenings /**< buffer to store the number of (variable) tightenings */
    2528 )
    2529{
    2530 SCIP_CONSHDLRDATA* conshdlrdata;
    2531 SCIP_EXPR* expr;
    2532 SCIP_EXPR_OWNERDATA* ownerdata;
    2533
    2534 assert(infeasible != NULL);
    2535 assert(ntightenings != NULL);
    2536
    2537 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2538 assert(conshdlrdata != NULL);
    2539
    2540 *ntightenings = 0;
    2541
    2542 /* main loop that calls reverse propagation for expressions on the queue
    2543 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
    2544 */
    2545 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
    2546 {
    2547 SCIP_INTERVAL propbounds;
    2548 int e;
    2549
    2550 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
    2551 assert(expr != NULL);
    2552
    2553 ownerdata = SCIPexprGetOwnerData(expr);
    2554 assert(ownerdata != NULL);
    2555
    2556 assert(ownerdata->inpropqueue);
    2557 /* mark that the expression is not in the queue anymore */
    2558 ownerdata->inpropqueue = FALSE;
    2559
    2560 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
    2561 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
    2562 */
    2563 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
    2564 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
    2565 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
    2566
    2567 /* this intersects propbounds with activity and auxvar bounds
    2568 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
    2569 * auxvar bounds separately, so disabling this for now
    2570 */
    2571#ifdef SCIP_DISABLED_CODE
    2572 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
    2574 {
    2575 *infeasible = TRUE;
    2576 break;
    2577 }
    2578#else
    2579 propbounds = ownerdata->propbounds;
    2580#endif
    2581
    2582 if( ownerdata->nenfos > 0 )
    2583 {
    2584 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
    2585 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
    2586 {
    2587 SCIP_NLHDLR* nlhdlr;
    2588 int nreds;
    2589
    2590 /* skip nlhdlr if it does not want to participate in activity computation */
    2591 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
    2592 continue;
    2593
    2594 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    2595 assert(nlhdlr != NULL);
    2596
    2597 /* call the reverseprop of the nlhdlr */
    2598#ifdef SCIP_DEBUG
    2599 SCIPdebugMsg(scip, "call reverse propagation for ");
    2600 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    2601 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
    2602#endif
    2603
    2604 nreds = 0;
    2605 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
    2606 assert(nreds >= 0);
    2607 *ntightenings += nreds;
    2608 }
    2609 }
    2611 {
    2612 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
    2613 SCIP_INTERVAL* childrenbounds;
    2614 int c;
    2615
    2616#ifdef SCIP_DEBUG
    2617 SCIPdebugMsg(scip, "call reverse propagation for ");
    2618 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    2619 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
    2620#endif
    2621
    2622 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
    2623 * been initialized in detectNlhdlr yet (nenfos < 0)
    2624 */
    2625 assert(ownerdata->nenfos < 0);
    2626
    2627 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
    2628 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
    2629 childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
    2630
    2631 /* call the reverseprop of the exprhdlr */
    2632 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
    2633
    2634 if( !*infeasible )
    2635 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
    2636 {
    2637 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
    2638 }
    2639
    2640 SCIPfreeBufferArray(scip, &childrenbounds);
    2641 }
    2642 }
    2643
    2644 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
    2645 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
    2646 {
    2647 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
    2648 assert(expr != NULL);
    2649
    2650 ownerdata = SCIPexprGetOwnerData(expr);
    2651 assert(ownerdata != NULL);
    2652
    2653 /* mark that the expression is not in the queue anymore */
    2654 ownerdata->inpropqueue = FALSE;
    2655 }
    2656
    2657 return SCIP_OKAY;
    2658}
    2659
    2660/** calls domain propagation for a given set of constraints
    2661 *
    2662 * The algorithm alternates calls of forward and reverse propagation.
    2663 * Forward propagation ensures that activity of expressions is up to date.
    2664 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
    2665 * [lhs,rhs] interval as starting point.
    2666 *
    2667 * The propagation algorithm works as follows:
    2668 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
    2669 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
    2670 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
    2671 * provide tighter bounds
    2672 * 3. apply reverse propagation to all collected expressions; don't explore
    2673 * sub-expressions which have not changed since the beginning of the propagation loop
    2674 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
    2675 *
    2676 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
    2677 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
    2678 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
    2679 *
    2680 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
    2681 * e.g., try less to propagate on convex constraints?
    2682 */
    2683static
    2685 SCIP* scip, /**< SCIP data structure */
    2686 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2687 SCIP_CONS** conss, /**< constraints to propagate */
    2688 int nconss, /**< total number of constraints */
    2689 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
    2690 SCIP_RESULT* result, /**< pointer to store the result */
    2691 int* nchgbds /**< buffer to add the number of changed bounds */
    2692 )
    2693{
    2694 SCIP_CONSHDLRDATA* conshdlrdata;
    2695 SCIP_CONSDATA* consdata;
    2696 SCIP_EXPR_OWNERDATA* ownerdata;
    2697 SCIP_Bool cutoff = FALSE;
    2698 SCIP_INTERVAL conssides;
    2699 int ntightenings;
    2700 int roundnr;
    2701 SCIP_EXPRITER* revpropcollectit = NULL;
    2702 int i;
    2703
    2704 assert(scip != NULL);
    2705 assert(conshdlr != NULL);
    2706 assert(conss != NULL);
    2707 assert(nconss >= 0);
    2708 assert(result != NULL);
    2709 assert(nchgbds != NULL);
    2710 assert(*nchgbds >= 0);
    2711
    2712 /* no constraints to propagate */
    2713 if( nconss == 0 )
    2714 {
    2715 *result = SCIP_DIDNOTRUN;
    2716 return SCIP_OKAY;
    2717 }
    2718
    2719 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2720 assert(conshdlrdata != NULL);
    2721#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
    2722 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
    2723#endif
    2724 assert(!conshdlrdata->globalbounds);
    2725
    2726 *result = SCIP_DIDNOTFIND;
    2727 roundnr = 0;
    2728
    2729 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
    2730 conshdlrdata->forceboundtightening = force;
    2731
    2732 /* invalidate all propbounds (probably not needed) */
    2733 ++conshdlrdata->curpropboundstag;
    2734
    2735 /* create iterator that we will use if we need to look at all auxvars */
    2736 if( conshdlrdata->propauxvars )
    2737 {
    2738 SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
    2739 }
    2740
    2741 /* main propagation loop */
    2742 do
    2743 {
    2744 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
    2745
    2746 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
    2747
    2748 /* apply forward propagation (update expression activities)
    2749 * and add promising root expressions into queue for reversepropagation
    2750 */
    2751 for( i = 0; i < nconss; ++i )
    2752 {
    2753 consdata = SCIPconsGetData(conss[i]);
    2754 assert(consdata != NULL);
    2755
    2756 /* skip deleted, non-active, or propagation-disabled constraints */
    2757 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
    2758 continue;
    2759
    2760 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
    2761 * activity didn't change
    2762 */
    2763 if( consdata->ispropagated )
    2764 continue;
    2765
    2766 /* update activities in expression */
    2767 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
    2768 SCIPdebugPrintCons(scip, conss[i], NULL);
    2769
    2770 ntightenings = 0;
    2771 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
    2772 assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
    2773
    2774 if( cutoff )
    2775 {
    2776 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
    2777 *result = SCIP_CUTOFF;
    2778 break;
    2779 }
    2780
    2781 ownerdata = SCIPexprGetOwnerData(consdata->expr);
    2782
    2783 /* TODO for a constraint that only has an auxvar for consdata->expr (e.g., convex quadratic), we could also just do the if(TRUE)-branch */
    2784 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
    2785 {
    2786 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
    2787 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
    2788 * so taking auxvar bounds is enough)
    2789 */
    2790 if( ownerdata->auxvar == NULL )
    2791 {
    2792 /* relax sides by SCIPepsilon() and handle infinite sides */
    2793 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
    2794 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
    2795 SCIPintervalSetBounds(&conssides, lhs, rhs);
    2796 }
    2797 else
    2798 {
    2799 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
    2800 }
    2801 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
    2802 }
    2803 else
    2804 {
    2805 /* check whether bounds of any auxvar used in constraint provides a tightening
    2806 * (for the root expression, bounds of auxvar are initially set to constraint sides)
    2807 * but skip exprs that have an auxvar, but do not participate in propagation
    2808 */
    2809 SCIP_EXPR* expr;
    2810
    2811 assert(revpropcollectit != NULL);
    2812 SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
    2813 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
    2814 {
    2815 ownerdata = SCIPexprGetOwnerData(expr);
    2816 assert(ownerdata != NULL);
    2817
    2818 if( ownerdata->auxvar == NULL )
    2819 continue;
    2820
    2821 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
    2822 continue;
    2823
    2824 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
    2825 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
    2826 }
    2827 }
    2828
    2829 if( cutoff )
    2830 {
    2831 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
    2832 *result = SCIP_CUTOFF;
    2833 break;
    2834 }
    2835
    2836 assert(ntightenings >= 0);
    2837 if( ntightenings > 0 )
    2838 {
    2839 *nchgbds += ntightenings;
    2840 *result = SCIP_REDUCEDDOM;
    2841 }
    2842
    2843 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
    2844 consdata->ispropagated = TRUE;
    2845 }
    2846
    2847 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
    2848 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
    2849 assert(ntightenings >= 0);
    2850 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
    2851
    2852 if( cutoff )
    2853 {
    2854 SCIPdebugMsg(scip, " -> cutoff\n");
    2855 *result = SCIP_CUTOFF;
    2856 break;
    2857 }
    2858
    2859 if( ntightenings > 0 )
    2860 {
    2861 *nchgbds += ntightenings;
    2862 *result = SCIP_REDUCEDDOM;
    2863 }
    2864 }
    2865 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
    2866
    2867 if( conshdlrdata->propauxvars )
    2868 {
    2869 SCIPfreeExpriter(&revpropcollectit);
    2870 }
    2871
    2872 conshdlrdata->forceboundtightening = FALSE;
    2873
    2874 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
    2875 ++conshdlrdata->curpropboundstag;
    2876
    2877 return SCIP_OKAY;
    2878}
    2879
    2880/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
    2881 *
    2882 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
    2883 *
    2884 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
    2885 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
    2886 */
    2887static
    2889 SCIP* scip, /**< SCIP data structure */
    2890 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2891 SCIP_CONS** conss, /**< constraints to propagate */
    2892 int nconss, /**< total number of constraints */
    2893 SCIP_RESULT* result, /**< pointer to store the result */
    2894 int* nchgbds /**< buffer to add the number of changed bounds */
    2895 )
    2896{
    2897 SCIP_CONSDATA* consdata;
    2898 SCIP_EXPRITER* it;
    2899 SCIP_EXPR* expr;
    2900 SCIP_EXPR_OWNERDATA* ownerdata;
    2901 SCIP_Bool cutoff = FALSE;
    2902 int ntightenings;
    2903 int c;
    2904 int e;
    2905
    2906 assert(scip != NULL);
    2907 assert(conshdlr != NULL);
    2908 assert(conss != NULL);
    2909 assert(nconss >= 0);
    2910 assert(result != NULL);
    2911 assert(nchgbds != NULL);
    2912 assert(*nchgbds >= 0);
    2913
    2914#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
    2915 assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
    2916#endif
    2917 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
    2918 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
    2919
    2920 *result = SCIP_DIDNOTFIND;
    2921
    2924
    2925 for( c = 0; c < nconss && !cutoff; ++c )
    2926 {
    2927 /* skip deleted, non-active, or propagation-disabled constraints */
    2928 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
    2929 continue;
    2930
    2931 consdata = SCIPconsGetData(conss[c]);
    2932 assert(consdata != NULL);
    2933
    2934 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
    2935 {
    2936 ownerdata = SCIPexprGetOwnerData(expr);
    2937 assert(ownerdata != NULL);
    2938
    2939 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
    2940 * this will propagate the current activity
    2941 */
    2942 for( e = 0; e < ownerdata->nenfos; ++e )
    2943 {
    2944 SCIP_NLHDLR* nlhdlr;
    2945 assert(ownerdata->enfos[e] != NULL);
    2946
    2947 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    2948 assert(nlhdlr != NULL);
    2949 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
    2950 continue;
    2951
    2952 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
    2953 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
    2954 ntightenings = 0;
    2955 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
    2956 SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
    2957
    2958 if( cutoff )
    2959 {
    2960 /* stop everything if we detected infeasibility */
    2961 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
    2962 *result = SCIP_CUTOFF;
    2963 break;
    2964 }
    2965
    2966 assert(ntightenings >= 0);
    2967 if( ntightenings > 0 )
    2968 {
    2969 *nchgbds += ntightenings;
    2970 *result = SCIP_REDUCEDDOM;
    2971 }
    2972 }
    2973 }
    2974 }
    2975
    2976 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
    2977 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
    2978 assert(ntightenings >= 0);
    2979
    2980 if( cutoff )
    2981 {
    2982 SCIPdebugMsg(scip, " -> cutoff\n");
    2983 *result = SCIP_CUTOFF;
    2984 }
    2985 else if( ntightenings > 0 )
    2986 {
    2987 *nchgbds += ntightenings;
    2988 *result = SCIP_REDUCEDDOM;
    2989 }
    2990
    2991 SCIPfreeExpriter(&it);
    2992
    2993 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
    2994 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
    2995
    2996 return SCIP_OKAY;
    2997}
    2998
    2999/** propagates variable locks through expression and adds locks to variables */
    3000static
    3002 SCIP* scip, /**< SCIP data structure */
    3003 SCIP_EXPR* expr, /**< expression */
    3004 int nlockspos, /**< number of positive locks */
    3005 int nlocksneg /**< number of negative locks */
    3006 )
    3007{
    3008 SCIP_EXPR_OWNERDATA* ownerdata;
    3009 SCIP_EXPRITER* it;
    3010 SCIP_EXPRITER_USERDATA ituserdata;
    3011
    3012 assert(expr != NULL);
    3013
    3014 /* if no locks, then nothing to propagate */
    3015 if( nlockspos == 0 && nlocksneg == 0 )
    3016 return SCIP_OKAY;
    3017
    3021 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
    3022
    3023 /* store locks in root node */
    3024 ituserdata.intvals[0] = nlockspos;
    3025 ituserdata.intvals[1] = nlocksneg;
    3026 SCIPexpriterSetCurrentUserData(it, ituserdata);
    3027
    3028 while( !SCIPexpriterIsEnd(it) )
    3029 {
    3030 /* collect locks */
    3031 ituserdata = SCIPexpriterGetCurrentUserData(it);
    3032 nlockspos = ituserdata.intvals[0];
    3033 nlocksneg = ituserdata.intvals[1];
    3034
    3035 ownerdata = SCIPexprGetOwnerData(expr);
    3036
    3037 switch( SCIPexpriterGetStageDFS(it) )
    3038 {
    3040 {
    3041 if( SCIPisExprVar(scip, expr) )
    3042 {
    3043 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
    3044 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
    3045 }
    3046
    3047 /* add locks to expression */
    3048 ownerdata->nlockspos += nlockspos;
    3049 ownerdata->nlocksneg += nlocksneg;
    3050
    3051 /* add monotonicity information if expression has been locked for the first time */
    3052 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
    3054 {
    3055 int i;
    3056
    3057 assert(ownerdata->monotonicity == NULL);
    3058 assert(ownerdata->monotonicitysize == 0);
    3059
    3060 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
    3061 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
    3062
    3063 /* store the monotonicity for each child */
    3064 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
    3065 {
    3066 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
    3067 }
    3068 }
    3069 break;
    3070 }
    3071
    3073 {
    3074 /* remove monotonicity information if expression has been unlocked */
    3075 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
    3076 {
    3077 assert(ownerdata->monotonicitysize > 0);
    3078 /* keep this assert for checking whether someone changed an expression without updating locks properly */
    3079 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
    3080
    3081 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
    3082 ownerdata->monotonicitysize = 0;
    3083 }
    3084 break;
    3085 }
    3086
    3088 {
    3089 SCIP_MONOTONE monotonicity;
    3090
    3091 /* get monotonicity of child */
    3092 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
    3093 * SCIPcallExprMonotonicity
    3094 */
    3095 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
    3096
    3097 /* compute resulting locks of the child expression */
    3098 switch( monotonicity )
    3099 {
    3100 case SCIP_MONOTONE_INC:
    3101 ituserdata.intvals[0] = nlockspos;
    3102 ituserdata.intvals[1] = nlocksneg;
    3103 break;
    3104 case SCIP_MONOTONE_DEC:
    3105 ituserdata.intvals[0] = nlocksneg;
    3106 ituserdata.intvals[1] = nlockspos;
    3107 break;
    3109 ituserdata.intvals[0] = nlockspos + nlocksneg;
    3110 ituserdata.intvals[1] = nlockspos + nlocksneg;
    3111 break;
    3113 ituserdata.intvals[0] = 0;
    3114 ituserdata.intvals[1] = 0;
    3115 break;
    3116 }
    3117 /* set locks in child expression */
    3118 SCIPexpriterSetChildUserData(it, ituserdata);
    3119
    3120 break;
    3121 }
    3122
    3123 default :
    3124 /* you should never be here */
    3125 SCIPABORT();
    3126 break;
    3127 }
    3128
    3129 expr = SCIPexpriterGetNext(it);
    3130 }
    3131
    3132 SCIPfreeExpriter(&it);
    3133
    3134 return SCIP_OKAY;
    3135}
    3136
    3137/** main function for adding locks to expressions and variables
    3138 *
    3139 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
    3140 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
    3141 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
    3142 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
    3143 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
    3144 * the computed monotonicity information of each expression until all locks of an expression have been removed,
    3145 * which implies that updating the monotonicity information during the next locking of this expression does not
    3146 * break existing locks.
    3147 *
    3148 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
    3149 * locks from an expression and repropagating them after the structural changes have been applied.
    3150 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
    3151 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
    3152 */
    3153static
    3155 SCIP* scip, /**< SCIP data structure */
    3156 SCIP_CONS* cons, /**< nonlinear constraint */
    3157 int nlockspos, /**< number of positive rounding locks */
    3158 int nlocksneg /**< number of negative rounding locks */
    3159 )
    3160{
    3161 SCIP_CONSDATA* consdata;
    3162
    3163 assert(cons != NULL);
    3164
    3165 if( nlockspos == 0 && nlocksneg == 0 )
    3166 return SCIP_OKAY;
    3167
    3168 consdata = SCIPconsGetData(cons);
    3169 assert(consdata != NULL);
    3170
    3171 /* no constraint sides -> nothing to lock */
    3172 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
    3173 return SCIP_OKAY;
    3174
    3175 /* remember locks */
    3176 consdata->nlockspos += nlockspos;
    3177 consdata->nlocksneg += nlocksneg;
    3178
    3179 assert(consdata->nlockspos >= 0);
    3180 assert(consdata->nlocksneg >= 0);
    3181
    3182 /* compute locks for lock propagation */
    3183 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
    3184 {
    3185 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg) );
    3186 }
    3187 else if( !SCIPisInfinity(scip, consdata->rhs) )
    3188 {
    3189 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg) );
    3190 }
    3191 else
    3192 {
    3193 assert(!SCIPisInfinity(scip, -consdata->lhs));
    3194 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos) );
    3195 }
    3196
    3197 return SCIP_OKAY;
    3198}
    3199
    3200/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
    3201static
    3203 SCIP* scip, /**< SCIP data structure */
    3204 SCIP_CONS* cons /**< nonlinear constraint */
    3205 )
    3206{
    3207 SCIP_CONSDATA* consdata;
    3208
    3209 assert(scip != NULL);
    3210 assert(cons != NULL);
    3211
    3212 consdata = SCIPconsGetData(cons);
    3213 assert(consdata != NULL);
    3214 assert(consdata->expr != NULL);
    3215
    3216 if( consdata->nlrow != NULL )
    3217 {
    3218 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
    3219 }
    3220
    3221 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
    3222 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
    3223 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
    3224
    3225 if( SCIPisExprSum(scip, consdata->expr) )
    3226 {
    3227 /* if root is a sum, then split into linear and nonlinear terms */
    3228 SCIP_EXPR* nonlinpart;
    3229 SCIP_EXPR* child;
    3230 SCIP_Real* coefs;
    3231 int i;
    3232
    3233 coefs = SCIPgetCoefsExprSum(consdata->expr);
    3234
    3235 /* constant term of sum */
    3236 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
    3237
    3238 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
    3239 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
    3240
    3241 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
    3242 {
    3243 child = SCIPexprGetChildren(consdata->expr)[i];
    3244 if( SCIPisExprVar(scip, child) )
    3245 {
    3246 /* linear term */
    3247 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
    3248 }
    3249 else
    3250 {
    3251 /* nonlinear term */
    3252 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
    3253 }
    3254 }
    3255
    3256 if( SCIPexprGetNChildren(nonlinpart) > 0 )
    3257 {
    3258 /* add expression to nlrow (this will make a copy) */
    3259 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
    3260 }
    3261 SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
    3262 }
    3263 else
    3264 {
    3265 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
    3266 }
    3267
    3268 return SCIP_OKAY;
    3269}
    3270
    3271/** compares enfodata by enforcement priority of nonlinear handler
    3272 *
    3273 * If handlers have same enforcement priority, then compare by detection priority, then by name.
    3274 */
    3275static
    3277{
    3278 SCIP_NLHDLR* h1;
    3279 SCIP_NLHDLR* h2;
    3280
    3281 assert(elem1 != NULL);
    3282 assert(elem2 != NULL);
    3283
    3284 h1 = ((EXPRENFO*)elem1)->nlhdlr;
    3285 h2 = ((EXPRENFO*)elem2)->nlhdlr;
    3286
    3287 assert(h1 != NULL);
    3288 assert(h2 != NULL);
    3289
    3292
    3295
    3296 return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
    3297}
    3298
    3299/** install nlhdlrs in one expression */
    3300static
    3302 SCIP* scip, /**< SCIP data structure */
    3303 SCIP_EXPR* expr, /**< expression for which to run detection routines */
    3304 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
    3305 )
    3306{
    3307 SCIP_EXPR_OWNERDATA* ownerdata;
    3308 SCIP_CONSHDLRDATA* conshdlrdata;
    3309 SCIP_NLHDLR_METHOD enforcemethodsallowed;
    3310 SCIP_NLHDLR_METHOD enforcemethods;
    3311 SCIP_NLHDLR_METHOD enforcemethodsnew;
    3312 SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
    3313 SCIP_NLHDLR_METHOD nlhdlrparticipating;
    3314 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
    3315 int enfossize; /* allocated length of expr->enfos array */
    3316 int h;
    3317
    3318 assert(expr != NULL);
    3319
    3320 ownerdata = SCIPexprGetOwnerData(expr);
    3321 assert(ownerdata != NULL);
    3322
    3323 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    3324 assert(conshdlrdata != NULL);
    3325 assert(conshdlrdata->auxvarid >= 0);
    3326 assert(!conshdlrdata->indetect);
    3327
    3328 /* there should be no enforcer yet and detection should not even have considered expr yet */
    3329 assert(ownerdata->nenfos < 0);
    3330 assert(ownerdata->enfos == NULL);
    3331
    3332 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
    3333 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
    3334 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
    3335 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
    3336 * - if no one uses activity, then do not need activity methods
    3337 */
    3338 enforcemethods = SCIP_NLHDLR_METHOD_NONE;
    3339 if( ownerdata->nauxvaruses == 0 )
    3340 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
    3341 else
    3342 {
    3343 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
    3344 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
    3345 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
    3346 enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
    3347 }
    3348 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
    3349 enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
    3350
    3351 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
    3352 assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
    3353
    3354 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
    3355 enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
    3356
    3357 ownerdata->nenfos = 0;
    3358 enfossize = 2;
    3359 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
    3360 conshdlrdata->indetect = TRUE;
    3361
    3362 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
    3363 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
    3364 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
    3365 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
    3366 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
    3367
    3368 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
    3369 {
    3370 SCIP_NLHDLR* nlhdlr;
    3371
    3372 nlhdlr = conshdlrdata->nlhdlrs[h];
    3373 assert(nlhdlr != NULL);
    3374
    3375 /* skip disabled nlhdlrs */
    3376 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
    3377 continue;
    3378
    3379 /* call detect routine of nlhdlr */
    3380 nlhdlrexprdata = NULL;
    3381 enforcemethodsnew = enforcemethods;
    3382 nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
    3383 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
    3384 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
    3385 /* coverity[var_deref_model] */
    3386 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
    3387
    3388 /* nlhdlr might have claimed more than needed: clean up sepa flags */
    3389 nlhdlrparticipating &= enforcemethodsallowed;
    3390
    3391 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
    3392 assert((enforcemethodsnew & enforcemethods) == enforcemethods);
    3393
    3394 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
    3395 * They are also cleaned up here to ensure that only the needed methods are claimed.
    3396 */
    3397 nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
    3398
    3399 /* nlhdlr needs to participate for the methods it is enforcing */
    3400 assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
    3401
    3402 if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
    3403 {
    3404 /* nlhdlr might not have detected anything, or all set flags might have been removed by
    3405 * clean up; in the latter case, we may need to free nlhdlrexprdata */
    3406
    3407 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
    3408 if( nlhdlrexprdata != NULL )
    3409 {
    3410 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
    3411 }
    3412 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
    3413 assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
    3414
    3415 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
    3416
    3417 continue;
    3418 }
    3419
    3420 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
    3421 SCIPnlhdlrGetName(nlhdlr),
    3422 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
    3423 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
    3424 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
    3425
    3426 /* store nlhdlr and its data */
    3427 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
    3428 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
    3429 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
    3430 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
    3431 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
    3432 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
    3433 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
    3434 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
    3435 ownerdata->nenfos++;
    3436
    3437 /* update enforcement flags */
    3438 enforcemethods = enforcemethodsnew;
    3439 }
    3440
    3441 conshdlrdata->indetect = FALSE;
    3442
    3443 /* stop if an enforcement method is missing but we are already in solving stage
    3444 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
    3445 */
    3446 if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
    3447 {
    3448 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
    3449 return SCIP_ERROR;
    3450 }
    3451
    3452 assert(ownerdata->nenfos > 0);
    3453
    3454 /* sort nonlinear handlers by enforcement priority, in decreasing order */
    3455 if( ownerdata->nenfos > 1 )
    3456 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
    3457
    3458 /* resize enfos array to be nenfos long */
    3459 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
    3460
    3461 return SCIP_OKAY;
    3462}
    3463
    3464/** detect nlhdlrs that can handle the expressions */
    3465static
    3467 SCIP* scip, /**< SCIP data structure */
    3468 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    3469 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
    3470 int nconss /**< total number of constraints */
    3471 )
    3472{
    3473 SCIP_CONSHDLRDATA* conshdlrdata;
    3474 SCIP_CONSDATA* consdata;
    3475 SCIP_EXPR* expr;
    3476 SCIP_EXPR_OWNERDATA* ownerdata;
    3477 SCIP_EXPRITER* it;
    3478 int i;
    3479
    3480 assert(conss != NULL || nconss == 0);
    3481 assert(nconss >= 0);
    3482 assert(SCIPgetStage(scip) >= SCIP_STAGE_PRESOLVING && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING); /* should only be called in presolve or initsolve or consactive */
    3483
    3484 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    3485 assert(conshdlrdata != NULL);
    3486
    3489
    3491 {
    3492 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
    3493 * for example, this happens if globally valid nonlinear constraints are added during the tree search
    3494 */
    3496 conshdlrdata->globalbounds = TRUE;
    3497 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
    3498 }
    3499
    3500 for( i = 0; i < nconss; ++i )
    3501 {
    3502 assert(conss != NULL && conss[i] != NULL);
    3503
    3504 consdata = SCIPconsGetData(conss[i]);
    3505 assert(consdata != NULL);
    3506 assert(consdata->expr != NULL);
    3507
    3508 /* if a constraint is separated, we currently need it to be initial, too
    3509 * this is because INITLP will create the auxiliary variables that are used for any separation
    3510 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
    3511 */
    3512 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
    3513
    3514 ownerdata = SCIPexprGetOwnerData(consdata->expr);
    3515 assert(ownerdata != NULL);
    3516
    3517 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
    3518 * then we would normally skip to run DETECT again
    3519 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
    3520 * thus, if expr is the root expression, we rerun DETECT
    3521 */
    3522 if( ownerdata->nenfos > 0 )
    3523 {
    3524 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
    3525 assert(ownerdata->nenfos < 0);
    3526 }
    3527
    3528 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
    3529 * this way we can treat the root expression like any other expression when enforcing via separation
    3530 * if constraint will be propagated, then register activity usage of root expression
    3531 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
    3532 */
    3533 conshdlrdata->indetect = TRUE;
    3536 SCIPconsIsPropagated(conss[i]),
    3537 FALSE, FALSE) );
    3538 conshdlrdata->indetect = FALSE;
    3539
    3540 /* presolveSingleLockedVars() may need the activity of product expressions in a sum expr that is in the root expr of a nonlinear constraint with only one finite side
    3541 * if this presolver may be run in the current presolve round (presoltiming=exhaustive could be added as additional criterion),
    3542 * then we ensure that a routine will be present to compute this activity (SCIPregisterExprUsageNonlinear actually updates activity already)
    3543 */
    3544 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd'
    3545 && (SCIPisInfinity(scip, -consdata->lhs) || SCIPisInfinity(scip, consdata->rhs)) && SCIPisExprSum(scip, consdata->expr) )
    3546 {
    3547 int c;
    3548 for( c = 0; c < SCIPexprGetNChildren(consdata->expr); ++c )
    3549 {
    3550 expr = SCIPexprGetChildren(consdata->expr)[c];
    3551 if( SCIPisExprProduct(scip, expr) )
    3552 {
    3554 }
    3555 }
    3556 }
    3557
    3558 /* compute integrality information for all subexpressions */
    3559 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
    3560
    3561 /* run detectNlhdlr on all expr where required */
    3562 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    3563 {
    3564 ownerdata = SCIPexprGetOwnerData(expr);
    3565 assert(ownerdata != NULL);
    3566
    3567 /* skip exprs that we already looked at */
    3568 if( ownerdata->nenfos >= 0 )
    3569 continue;
    3570
    3571 /* if there is use of the auxvar, then someone requires that
    3572 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
    3573 * thus, we need to find nlhdlrs that separate or estimate
    3574 * if there is use of the activity, then there is someone requiring that
    3575 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
    3576 * thus, we need to find nlhdlrs that do interval-evaluation
    3577 */
    3578 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
    3579 {
    3580 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
    3581
    3582 assert(ownerdata->nenfos >= 0);
    3583 }
    3584 else
    3585 {
    3586 /* remember that we looked at this expression during detectNlhdlrs
    3587 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
    3588 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
    3589 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
    3590 */
    3591 ownerdata->nenfos = 0;
    3592 }
    3593 }
    3594
    3595 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
    3596 if( SCIPconsIsPropagated(conss[i]) )
    3597 consdata->ispropagated = FALSE;
    3598 }
    3599
    3601 {
    3602 /* ensure that the local bounds are used again when reevaluating the expressions later;
    3603 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
    3604 */
    3606 conshdlrdata->globalbounds = FALSE;
    3607 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
    3608 }
    3609 else
    3610 {
    3611 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
    3613 }
    3614
    3615 SCIPfreeExpriter(&it);
    3616
    3617 return SCIP_OKAY;
    3618}
    3619
    3620/** initializes (pre)solving data of constraints
    3621 *
    3622 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
    3623 * not be modified.
    3624 * In particular, this function
    3625 * - runs the detection method of nlhldrs
    3626 * - looks for unlocked linear variables
    3627 * - checks curvature (if not in presolve)
    3628 * - creates and add row to NLP (if not in presolve)
    3629 *
    3630 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
    3631 * e.g., it should be called in INITSOL and for constraints that are added during solve.
    3632 */
    3633static
    3635 SCIP* scip, /**< SCIP data structure */
    3636 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    3637 SCIP_CONS** conss, /**< constraints */
    3638 int nconss /**< number of constraints */
    3639 )
    3640{
    3641 int c;
    3642
    3643 for( c = 0; c < nconss; ++c )
    3644 {
    3645 /* check for a linear variable that can be increase or decreased without harming feasibility */
    3646 findUnlockedLinearVar(scip, conss[c]);
    3647
    3649 {
    3650 SCIP_CONSDATA* consdata;
    3651 SCIP_Bool success = FALSE;
    3652
    3653 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
    3654 assert(consdata != NULL);
    3655 assert(consdata->expr != NULL);
    3656
    3657 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
    3658 {
    3659 /* call the curvature detection algorithm of the convex nonlinear handler
    3660 * Check only for those curvature that may result in a convex inequality, i.e.,
    3661 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
    3662 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
    3663 */
    3664 if( !SCIPisInfinity(scip, -consdata->lhs) )
    3665 {
    3666 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
    3667 if( success )
    3668 consdata->curv = SCIP_EXPRCURV_CONCAVE;
    3669 }
    3670 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
    3671 {
    3672 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
    3673 if( success )
    3674 consdata->curv = SCIP_EXPRCURV_CONVEX;
    3675 }
    3676 }
    3677 else
    3678 {
    3679 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
    3680 {
    3681 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
    3682 consdata->curv = SCIP_EXPRCURV_LINEAR;
    3683 }
    3684 else
    3685 {
    3686 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
    3687 }
    3688 }
    3689 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
    3690
    3691 /* add nlrow representation to NLP, if NLP had been constructed */
    3692 if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
    3693 {
    3694 if( consdata->nlrow == NULL )
    3695 {
    3696 SCIP_CALL( createNlRow(scip, conss[c]) );
    3697 assert(consdata->nlrow != NULL);
    3698 }
    3699 SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
    3700 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
    3701 }
    3702 }
    3703 }
    3704
    3705 /* register non linear handlers */
    3706 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
    3707
    3708 return SCIP_OKAY;
    3709}
    3710
    3711/** deinitializes (pre)solving data of constraints
    3712 *
    3713 * This removes the initialization data created in initSolve().
    3714 *
    3715 * This function can be called in presolve and solve.
    3716 *
    3717 * TODO At the moment, it should not be called for a constraint if there are other constraints
    3718 * that use the same expressions but still require their nlhdlr.
    3719 * We should probably only decrement the auxvar and activity usage for the root expr and then
    3720 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
    3721 */
    3722static
    3724 SCIP* scip, /**< SCIP data structure */
    3725 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    3726 SCIP_CONS** conss, /**< constraints */
    3727 int nconss /**< number of constraints */
    3728 )
    3729{
    3730 SCIP_EXPRITER* it;
    3731 SCIP_EXPR* expr;
    3732 SCIP_CONSDATA* consdata;
    3733 SCIP_Bool rootactivityvalid;
    3734 int c;
    3735
    3739
    3740 /* call deinitialization callbacks of expression and nonlinear handlers
    3741 * free nonlinear handlers information from expressions
    3742 * remove auxiliary variables and nactivityuses counts from expressions
    3743 */
    3744 for( c = 0; c < nconss; ++c )
    3745 {
    3746 assert(conss != NULL);
    3747 assert(conss[c] != NULL);
    3748
    3749 consdata = SCIPconsGetData(conss[c]);
    3750 assert(consdata != NULL);
    3751 assert(consdata->expr != NULL);
    3752
    3753 /* check and remember whether activity in root is valid */
    3754 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
    3755
    3756 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    3757 {
    3758 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
    3759
    3760 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
    3761 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
    3762
    3763 /* remove quadratic info */
    3765
    3766 if( rootactivityvalid )
    3767 {
    3768 /* ensure activity is valid if consdata->expr activity is valid
    3769 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
    3770 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
    3771 * so this childs activity would be invalid, which can generate confusion
    3772 */
    3774 }
    3775 }
    3776
    3777 if( consdata->nlrow != NULL )
    3778 {
    3779 /* remove row from NLP, if still in solving
    3780 * if we are in exitsolve, the whole NLP will be freed anyway
    3781 */
    3783 {
    3784 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
    3785 }
    3786
    3787 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
    3788 }
    3789
    3790 /* forget about linear variables that can be increased or decreased without harming feasibility */
    3791 consdata->linvardecr = NULL;
    3792 consdata->linvarincr = NULL;
    3793
    3794 /* forget about curvature */
    3795 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
    3796 }
    3797
    3798 SCIPfreeExpriter(&it);
    3799
    3800 return SCIP_OKAY;
    3801}
    3802
    3803/** helper method to decide whether a given expression is product of at least two binary variables */
    3804static
    3806 SCIP* scip, /**< SCIP data structure */
    3807 SCIP_EXPR* expr /**< expression */
    3808 )
    3809{
    3810 int i;
    3811
    3812 assert(expr != NULL);
    3813
    3814 /* check whether the expression is a product */
    3815 if( !SCIPisExprProduct(scip, expr) )
    3816 return FALSE;
    3817
    3818 /* don't consider products with a coefficient != 1 and products with a single child
    3819 * simplification will take care of this expression later
    3820 */
    3821 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
    3822 return FALSE;
    3823
    3824 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
    3825 {
    3826 SCIP_EXPR* child;
    3827 SCIP_VAR* var;
    3828
    3829 child = SCIPexprGetChildren(expr)[i];
    3830 assert(child != NULL);
    3831
    3832 if( !SCIPisExprVar(scip, child) )
    3833 return FALSE;
    3834
    3835 var = SCIPgetVarExprVar(child);
    3836
    3837 /* check whether variable is binary, in any feasible solution
    3838 * we need to forbid weakly implied binary variables because cons_and wouldn't ensure that the
    3839 * product condition holds in any feasible solution (i.e., when vars may not be at bounds) in this case,
    3840 * which would lead to accepting solutions that are not feasible in the original (non-reformulated) cons
    3841 */
    3843 return FALSE;
    3844 }
    3845
    3846 return TRUE;
    3847}
    3848
    3849/** helper method to collect all bilinear binary product terms */
    3850static
    3852 SCIP* scip, /**< SCIP data structure */
    3853 SCIP_EXPR* sumexpr, /**< sum expression */
    3854 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
    3855 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
    3856 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
    3857 int* nterms /**< pointer to store the total number of bilinear binary terms */
    3858 )
    3859{
    3860 int i;
    3861
    3862 assert(sumexpr != NULL);
    3863 assert(SCIPisExprSum(scip, sumexpr));
    3864 assert(xs != NULL);
    3865 assert(ys != NULL);
    3866 assert(childidxs != NULL);
    3867 assert(nterms != NULL);
    3868
    3869 *nterms = 0;
    3870
    3871 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
    3872 {
    3873 SCIP_EXPR* child;
    3874
    3875 child = SCIPexprGetChildren(sumexpr)[i];
    3876 assert(child != NULL);
    3877
    3878 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
    3879 {
    3882
    3883 assert(x != NULL);
    3884 assert(y != NULL);
    3885
    3886 if( x != y )
    3887 {
    3888 xs[*nterms] = x;
    3889 ys[*nterms] = y;
    3890 childidxs[*nterms] = i;
    3891 ++(*nterms);
    3892 }
    3893 }
    3894 }
    3895
    3896 return SCIP_OKAY;
    3897}
    3898
    3899/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
    3900static
    3902 SCIP* scip, /**< SCIP data structure */
    3903 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    3904 SCIP_CONS* cons, /**< constraint */
    3905 SCIP_VAR* facvar, /**< variable that has been factorized */
    3906 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
    3907 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
    3908 int nvars, /**< total number of variables in sum_j c_ij x_j */
    3909 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
    3910 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
    3911 )
    3912{
    3913 SCIP_VAR* auxvar;
    3914 SCIP_CONS* newcons;
    3915 SCIP_Real minact = 0.0;
    3916 SCIP_Real maxact = 0.0;
    3918 char name [SCIP_MAXSTRLEN];
    3919 int i;
    3920
    3921 assert(facvar != NULL);
    3922 assert(vars != NULL);
    3923 assert(nvars > 1);
    3924 assert(newexpr != NULL);
    3925
    3926 /* compute minimum and maximum activity of sum_j c_ij x_j */
    3927 /* TODO could compute minact and maxact for facvar=0 and facvar=1 separately, taking implied bounds into account, allowing for possibly tighter big-M's below */
    3928 for( i = 0; i < nvars; ++i )
    3929 {
    3930 minact += MIN(coefs[i], 0.0);
    3931 maxact += MAX(coefs[i], 0.0);
    3932 assert(SCIPvarIsIntegral(vars[i]));
    3934
    3935 if( impltype != SCIP_IMPLINTTYPE_NONE && !SCIPisIntegral(scip, coefs[i]) )
    3936 impltype = SCIP_IMPLINTTYPE_NONE;
    3937 }
    3938 assert(minact <= maxact);
    3939
    3940 /* create and add auxiliary variable */
    3941 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    3942 SCIP_CALL( SCIPcreateVarImpl(scip, &auxvar, name, minact, maxact, 0.0, SCIP_VARTYPE_CONTINUOUS, impltype,
    3943 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    3944 SCIP_CALL( SCIPaddVar(scip, auxvar) );
    3945
    3946#ifdef WITH_DEBUG_SOLUTION
    3947 if( SCIPdebugIsMainscip(scip) )
    3948 {
    3949 SCIP_Real debugsolval; /* value of auxvar in debug solution */
    3950 SCIP_Real val;
    3951
    3952 /* compute value of new variable in debug solution */
    3953 /* first \sum_j c_{ij} x_j (coefs[j] * vars[j]) */
    3954 debugsolval = 0.0;
    3955 for( i = 0; i < nvars; ++i )
    3956 {
    3957 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[i], &val) );
    3958 debugsolval += coefs[i] * val;
    3959 }
    3960
    3961 /* now multiply by x_i (facvar) */
    3962 SCIP_CALL( SCIPdebugGetSolVal(scip, facvar, &val) );
    3963 debugsolval *= val;
    3964
    3965 /* store debug solution value of auxiliary variable */
    3966 SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugsolval) );
    3967 }
    3968#endif
    3969
    3970 /* create and add z - maxact x <= 0 */
    3971 if( !SCIPisZero(scip, maxact) )
    3972 {
    3973 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    3974 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
    3975 SCIP_CALL( SCIPaddCons(scip, newcons) );
    3976 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    3977 if( naddconss != NULL )
    3978 ++(*naddconss);
    3979 }
    3980
    3981 /* create and add 0 <= z - minact x */
    3982 if( !SCIPisZero(scip, minact) )
    3983 {
    3984 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    3985 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
    3986 SCIP_CALL( SCIPaddCons(scip, newcons) );
    3987 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    3988 if( naddconss != NULL )
    3989 ++(*naddconss);
    3990 }
    3991
    3992 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
    3993 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    3994 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
    3995 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
    3996 if( !SCIPisZero(scip, minact) )
    3997 {
    3998 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
    3999 }
    4000 SCIP_CALL( SCIPaddCons(scip, newcons) );
    4001 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    4002 if( naddconss != NULL )
    4003 ++(*naddconss);
    4004
    4005 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
    4006 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    4007 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
    4008 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
    4009 if( !SCIPisZero(scip, maxact) )
    4010 {
    4011 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
    4012 }
    4013 SCIP_CALL( SCIPaddCons(scip, newcons) );
    4014 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    4015 if( naddconss != NULL )
    4016 ++(*naddconss);
    4017
    4018 /* create variable expression */
    4019 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
    4020
    4021 /* release auxvar */
    4022 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
    4023
    4024 return SCIP_OKAY;
    4025}
    4026
    4027/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
    4028static
    4030 SCIP* scip, /**< SCIP data structure */
    4031 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4032 SCIP_CONS* cons, /**< constraint */
    4033 SCIP_EXPR* sumexpr, /**< expression */
    4034 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
    4035 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
    4036 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
    4037 )
    4038{
    4039 SCIP_EXPR** exprs = NULL;
    4040 SCIP_VAR** tmpvars = NULL;
    4041 SCIP_VAR** vars = NULL;
    4042 SCIP_VAR** xs = NULL;
    4043 SCIP_VAR** ys = NULL;
    4044 SCIP_Real* exprcoefs = NULL;
    4045 SCIP_Real* tmpcoefs = NULL;
    4046 SCIP_Real* sumcoefs;
    4047 SCIP_Bool* isused = NULL;
    4048 int* childidxs = NULL;
    4049 int* count = NULL;
    4050 int nchildren;
    4051 int nexprs = 0;
    4052 int nterms;
    4053 int nvars;
    4054 int ntotalvars;
    4055 int i;
    4056
    4057 assert(sumexpr != NULL);
    4058 assert(minterms > 1);
    4059 assert(newexpr != NULL);
    4060
    4061 *newexpr = NULL;
    4062
    4063 /* check whether sumexpr is indeed a sum */
    4064 if( !SCIPisExprSum(scip, sumexpr) )
    4065 return SCIP_OKAY;
    4066
    4067 nchildren = SCIPexprGetNChildren(sumexpr);
    4068 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
    4069 nvars = SCIPgetNVars(scip);
    4070 ntotalvars = SCIPgetNTotalVars(scip);
    4071
    4072 /* check whether there are enough terms available */
    4073 if( nchildren < minterms )
    4074 return SCIP_OKAY;
    4075
    4076 /* allocate memory */
    4077 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
    4078 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
    4079 SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
    4080
    4081 /* collect all bilinear binary product terms */
    4082 SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
    4083
    4084 /* check whether there are enough terms available */
    4085 if( nterms < minterms )
    4086 goto TERMINATE;
    4087
    4088 /* store how often each variable appears in a bilinear binary product */
    4090 SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
    4091 SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
    4092
    4093 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
    4094 SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
    4095 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
    4096 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
    4097
    4098 for( i = 0; i < nterms; ++i )
    4099 {
    4100 int xidx;
    4101 int yidx;
    4102
    4103 assert(xs[i] != NULL);
    4104 assert(ys[i] != NULL);
    4105
    4106 xidx = SCIPvarGetIndex(xs[i]);
    4107 assert(xidx < ntotalvars);
    4108 yidx = SCIPvarGetIndex(ys[i]);
    4109 assert(yidx < ntotalvars);
    4110
    4111 ++count[xidx];
    4112 ++count[yidx];
    4113
    4114 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
    4115 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
    4116 }
    4117
    4118 /* sort variables; don't change order of count array because it depends on problem indices */
    4119 {
    4120 int* tmpcount;
    4121
    4122 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
    4123 SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
    4124 SCIPfreeBufferArray(scip, &tmpcount);
    4125 }
    4126
    4127 for( i = 0; i < nvars; ++i )
    4128 {
    4129 SCIP_VAR* facvar = vars[i];
    4130 int ntmpvars = 0;
    4131 int j;
    4132
    4133 /* skip candidate if there are not enough terms left */
    4134 if( count[SCIPvarGetIndex(vars[i])] < minterms )
    4135 continue;
    4136
    4137 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
    4138
    4139 /* collect variables for x_i * sum_j c_ij x_j */
    4140 for( j = 0; j < nterms; ++j )
    4141 {
    4142 int childidx = childidxs[j];
    4143 assert(childidx >= 0 && childidx < nchildren);
    4144
    4145 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
    4146 {
    4147 SCIP_Real coef;
    4148 int xidx;
    4149 int yidx;
    4150
    4151 coef = sumcoefs[childidx];
    4152 assert(coef != 0.0);
    4153
    4154 /* collect corresponding variable */
    4155 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
    4156 tmpcoefs[ntmpvars] = coef;
    4157 ++ntmpvars;
    4158
    4159 /* update counters */
    4160 xidx = SCIPvarGetIndex(xs[j]);
    4161 assert(xidx < ntotalvars);
    4162 yidx = SCIPvarGetIndex(ys[j]);
    4163 assert(yidx < ntotalvars);
    4164 --count[xidx];
    4165 --count[yidx];
    4166 assert(count[xidx] >= 0);
    4167 assert(count[yidx] >= 0);
    4168
    4169 /* mark term to be used */
    4170 isused[childidx] = TRUE;
    4171 }
    4172 }
    4173 assert(ntmpvars >= minterms);
    4174 assert(SCIPvarGetIndex(facvar) < ntotalvars);
    4175 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
    4176
    4177 /* create required constraints and store the generated expression */
    4178 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
    4179 exprcoefs[nexprs] = 1.0;
    4180 ++nexprs;
    4181 }
    4182
    4183 /* factorization was only successful if at least one expression has been generated */
    4184 if( nexprs > 0 )
    4185 {
    4186 int nexprsold = nexprs;
    4187
    4188 /* add all children of the sum that have not been used */
    4189 for( i = 0; i < nchildren; ++i )
    4190 {
    4191 if( !isused[i] )
    4192 {
    4193 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
    4194 exprcoefs[nexprs] = sumcoefs[i];
    4195 ++nexprs;
    4196 }
    4197 }
    4198
    4199 /* create a new sum expression */
    4200 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
    4201
    4202 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
    4203 for( i = 0; i < nexprsold; ++i )
    4204 {
    4205 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
    4206 }
    4207 }
    4208
    4209TERMINATE:
    4210 /* free memory */
    4211 SCIPfreeBufferArrayNull(scip, &tmpcoefs);
    4212 SCIPfreeBufferArrayNull(scip, &tmpvars);
    4213 SCIPfreeBufferArrayNull(scip, &exprcoefs);
    4216 SCIPfreeBufferArrayNull(scip, &isused);
    4218 SCIPfreeBufferArray(scip, &childidxs);
    4221
    4222 return SCIP_OKAY;
    4223}
    4224
    4225/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
    4226static
    4228 SCIP* scip, /**< SCIP data structure */
    4229 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4230 SCIP_EXPR* prodexpr, /**< product expression */
    4231 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
    4232 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
    4233 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
    4234 )
    4235{
    4236 SCIP_VAR** vars;
    4237 SCIP_CONS* cons;
    4238 SCIP_Real* coefs;
    4239 SCIP_VAR* w;
    4240 char* name;
    4241 int nchildren;
    4242 int i;
    4243
    4244 assert(conshdlr != NULL);
    4245 assert(prodexpr != NULL);
    4246 assert(SCIPisExprProduct(scip, prodexpr));
    4247 assert(newexpr != NULL);
    4248
    4249 nchildren = SCIPexprGetNChildren(prodexpr);
    4250 assert(nchildren >= 2);
    4251
    4252 /* memory to store the variables of the variable expressions (+1 for w) and their name */
    4253 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
    4254 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
    4255 SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
    4256
    4257 /* prepare the names of the variable and the constraints */
    4258 /* coverity[secure_coding] */
    4259 strcpy(name, "binreform");
    4260 for( i = 0; i < nchildren; ++i )
    4261 {
    4262 vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
    4263 coefs[i] = 1.0;
    4264 assert(vars[i] != NULL);
    4265 (void) strcat(name, "_");
    4266 (void) strcat(name, SCIPvarGetName(vars[i]));
    4267
    4268 assert(SCIPvarIsBinary(vars[i]) && SCIPvarGetImplType(vars[i]) != SCIP_IMPLINTTYPE_WEAK);
    4269 }
    4270
    4271 /* create and add variable */
    4272 SCIP_CALL( SCIPcreateVarImpl(scip, &w, name, 0.0, 1.0, 0.0,
    4274 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    4276 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
    4277
    4278#ifdef WITH_DEBUG_SOLUTION
    4279 if( SCIPdebugIsMainscip(scip) )
    4280 {
    4281 SCIP_Real debugsolval; /* value of auxvar in debug solution */
    4282 SCIP_Real val;
    4283
    4284 /* compute value of new variable in debug solution (\prod_i vars[i]) */
    4285 debugsolval = 1.0;
    4286 for( i = 0; i < nchildren; ++i )
    4287 {
    4288 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[i], &val) );
    4289 debugsolval *= val;
    4290 }
    4291
    4292 /* store debug solution value of auxiliary variable */
    4293 SCIP_CALL( SCIPdebugAddSolVal(scip, w, debugsolval) );
    4294 }
    4295#endif
    4296
    4297 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
    4298 if( nchildren == 2 && !empathy4and )
    4299 {
    4300 SCIP_VAR* x = vars[0];
    4301 SCIP_VAR* y = vars[1];
    4302
    4303 assert(x != NULL);
    4304 assert(y != NULL);
    4305 assert(x != y);
    4306
    4307 /* create and add x - w >= 0 */
    4308 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
    4309 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
    4310 SCIP_CALL( SCIPaddCons(scip, cons) );
    4311 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    4312
    4313 /* create and add y - w >= 0 */
    4314 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
    4315 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
    4316 SCIP_CALL( SCIPaddCons(scip, cons) );
    4317 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    4318
    4319 /* create and add x + y - w <= 1 */
    4320 vars[2] = w;
    4321 coefs[2] = -1.0;
    4322 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
    4323 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
    4324 SCIP_CALL( SCIPaddCons(scip, cons) );
    4325 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    4326
    4327 /* update number of added constraints */
    4328 if( naddconss != NULL )
    4329 *naddconss += 3;
    4330 }
    4331 else
    4332 {
    4333 /* create, add, and release AND constraint */
    4334 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
    4335 SCIP_CALL( SCIPaddCons(scip, cons) );
    4336 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    4337 SCIPdebugMsg(scip, " create AND constraint\n");
    4338
    4339 /* update number of added constraints */
    4340 if( naddconss != NULL )
    4341 *naddconss += 1;
    4342 }
    4343
    4344 /* create variable expression */
    4345 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
    4346
    4347 /* release created variable */
    4349
    4350 /* free memory */
    4351 SCIPfreeBufferArray(scip, &name);
    4352 SCIPfreeBufferArray(scip, &coefs);
    4353 SCIPfreeBufferArray(scip, &vars);
    4354
    4355 return SCIP_OKAY;
    4356}
    4357
    4358/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
    4359static
    4361 SCIP* scip, /**< SCIP data structure */
    4362 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4363 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
    4364 SCIP_EXPR* prodexpr, /**< product expression */
    4365 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
    4366 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
    4367 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
    4368 )
    4369{
    4370 SCIP_CONSHDLRDATA* conshdlrdata;
    4371 int nchildren;
    4372
    4373 assert(prodexpr != NULL);
    4374 assert(newexpr != NULL);
    4375
    4376 *newexpr = NULL;
    4377
    4378 /* only consider products of binary variables */
    4379 if( !isBinaryProduct(scip, prodexpr) )
    4380 return SCIP_OKAY;
    4381
    4382 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4383 assert(conshdlrdata != NULL);
    4384 nchildren = SCIPexprGetNChildren(prodexpr);
    4385 assert(nchildren >= 2);
    4386
    4387 /* check whether there is already an expression that represents the product */
    4388 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
    4389 {
    4390 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
    4391 assert(*newexpr != NULL);
    4392
    4393 /* capture expression */
    4394 SCIPcaptureExpr(*newexpr);
    4395 }
    4396 else
    4397 {
    4398 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
    4399
    4400 if( nchildren == 2 )
    4401 {
    4402 SCIP_CLIQUE** xcliques;
    4403 SCIP_CONS* clqcons;
    4404 SCIP_VAR* clqvars[2];
    4405 SCIP_VAR* x;
    4406 SCIP_VAR* y;
    4407 SCIP_Bool found_clique = FALSE;
    4408 char clqname[SCIP_MAXSTRLEN];
    4409 int c;
    4410
    4411 /* get variables from the product expression */
    4412 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
    4413 assert(x != NULL);
    4414 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
    4415 assert(y != NULL);
    4416 assert(x != y);
    4417
    4418 /* first try to find a clique containing both variables */
    4419 xcliques = SCIPvarGetCliques(x, TRUE);
    4420
    4421 /* look in cliques containing x */
    4422 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
    4423 {
    4424 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
    4425 {
    4426 /* add clique as explicit set packing constraint to preserve model completeness */
    4427 clqvars[0] = x;
    4428 clqvars[1] = y;
    4429 (void) SCIPsnprintf(clqname, SCIP_MAXSTRLEN, "binreform_%s_%s",
    4430 SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]));
    4431 SCIP_CALL( SCIPcreateConsBasicSetpack(scip, &clqcons, clqname, 2, clqvars) );
    4432 SCIP_CALL( SCIPaddCons(scip, clqcons) );
    4433 SCIP_CALL( SCIPreleaseCons(scip, &clqcons) );
    4434
    4435 /* create zero value expression */
    4436 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
    4437
    4438 if( naddconss != NULL )
    4439 *naddconss += 1;
    4440 if( nchgcoefs != NULL )
    4441 *nchgcoefs += 1;
    4442
    4443 found_clique = TRUE;
    4444 break;
    4445 }
    4446
    4447 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
    4448 {
    4449 /* add clique as explicit set packing constraint: x + (1-y) <= 1 */
    4450 clqvars[0] = x;
    4451 SCIP_CALL( SCIPgetNegatedVar(scip, y, &clqvars[1]) );
    4452 (void) SCIPsnprintf(clqname, SCIP_MAXSTRLEN, "binreform_%s_%s",
    4453 SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]));
    4454 SCIP_CALL( SCIPcreateConsBasicSetpack(scip, &clqcons, clqname, 2, clqvars) );
    4455 SCIP_CALL( SCIPaddCons(scip, clqcons) );
    4456 SCIP_CALL( SCIPreleaseCons(scip, &clqcons) );
    4457
    4458 /* create variable expression for x */
    4459 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
    4460
    4461 if( naddconss != NULL )
    4462 *naddconss += 1;
    4463 if( nchgcoefs != NULL )
    4464 *nchgcoefs += 2;
    4465
    4466 found_clique = TRUE;
    4467 break;
    4468 }
    4469 }
    4470
    4471 if( !found_clique )
    4472 {
    4473 xcliques = SCIPvarGetCliques(x, FALSE);
    4474
    4475 /* look in cliques containing complement of x */
    4476 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
    4477 {
    4478 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
    4479 {
    4480 /* add clique as explicit set packing constraint: (1-x) + y <= 1 */
    4481 SCIP_CALL( SCIPgetNegatedVar(scip, x, &clqvars[0]) );
    4482 clqvars[1] = y;
    4483 (void) SCIPsnprintf(clqname, SCIP_MAXSTRLEN, "binreform_%s_%s",
    4484 SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]));
    4485 SCIP_CALL( SCIPcreateConsBasicSetpack(scip, &clqcons, clqname, 2, clqvars) );
    4486 SCIP_CALL( SCIPaddCons(scip, clqcons) );
    4487 SCIP_CALL( SCIPreleaseCons(scip, &clqcons) );
    4488
    4489 /* create variable expression for y */
    4490 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
    4491
    4492 if( naddconss != NULL )
    4493 *naddconss += 1;
    4494 if( nchgcoefs != NULL )
    4495 *nchgcoefs += 1;
    4496
    4497 found_clique = TRUE;
    4498 break;
    4499 }
    4500
    4501 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
    4502 {
    4503 /* add clique as explicit set covering constraint: x + y >= 1 */
    4504 clqvars[0] = x;
    4505 clqvars[1] = y;
    4506 (void) SCIPsnprintf(clqname, SCIP_MAXSTRLEN, "binreform_%s_%s",
    4507 SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]));
    4508 SCIP_CALL( SCIPcreateConsBasicSetcover(scip, &clqcons, clqname, 2, clqvars) );
    4509 SCIP_CALL( SCIPaddCons(scip, clqcons) );
    4510 SCIP_CALL( SCIPreleaseCons(scip, &clqcons) );
    4511
    4512 /* create sum expression */
    4513 SCIP_EXPR* sum_children[2];
    4514 SCIP_Real sum_coefs[2];
    4515 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
    4516 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
    4517 sum_coefs[0] = 1.0;
    4518 sum_coefs[1] = 1.0;
    4519 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
    4520
    4521 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
    4522 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
    4523
    4524 if( naddconss != NULL )
    4525 *naddconss += 1;
    4526 if( nchgcoefs != NULL )
    4527 *nchgcoefs += 3;
    4528
    4529 found_clique = TRUE;
    4530 break;
    4531 }
    4532 }
    4533 }
    4534
    4535 /* if the variables are not in a clique, do standard linearization */
    4536 if( !found_clique )
    4537 {
    4538 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
    4539 }
    4540 }
    4541 else
    4542 {
    4543 /* linearize binary product using an AND constraint because nchildren > 2 */
    4544 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
    4545 }
    4546
    4547 /* hash variable expression */
    4548 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
    4549 }
    4550
    4551 return SCIP_OKAY;
    4552}
    4553
    4554/** helper function to replace binary products in a given constraint */
    4555static
    4557 SCIP* scip, /**< SCIP data structure */
    4558 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4559 SCIP_CONS* cons, /**< constraint */
    4560 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
    4561 SCIP_EXPRITER* it, /**< expression iterator */
    4562 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
    4563 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
    4564 )
    4565{
    4566 SCIP_CONSHDLRDATA* conshdlrdata;
    4567 SCIP_CONSDATA* consdata;
    4568 SCIP_EXPR* expr;
    4569
    4570 assert(conshdlr != NULL);
    4571 assert(cons != NULL);
    4572 assert(exprmap != NULL);
    4573 assert(it != NULL);
    4574
    4575 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4576 assert(conshdlrdata != NULL);
    4577
    4578 consdata = SCIPconsGetData(cons);
    4579 assert(consdata != NULL);
    4580 assert(consdata->expr != NULL);
    4581
    4582 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
    4583
    4584 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    4585 {
    4586 SCIP_EXPR* newexpr = NULL;
    4587 SCIP_EXPR* childexpr;
    4588 int childexpridx;
    4589
    4590 childexpridx = SCIPexpriterGetChildIdxDFS(it);
    4591 assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
    4592 childexpr = SCIPexpriterGetChildExprDFS(it);
    4593 assert(childexpr != NULL);
    4594
    4595 /* try to factorize variables in a sum expression that contains several products of binary variables */
    4596 if( conshdlrdata->reformbinprodsfac > 1 )
    4597 {
    4598 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
    4599 }
    4600
    4601 /* try to create an expression that represents a product of binary variables */
    4602 if( newexpr == NULL )
    4603 {
    4604 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
    4605 }
    4606
    4607 if( newexpr != NULL )
    4608 {
    4609 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
    4610
    4611 /* replace product expression */
    4612 SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
    4613
    4614 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
    4615 SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
    4616
    4617 /* mark the constraint to not be simplified anymore */
    4618 consdata->issimplified = FALSE;
    4619 }
    4620 }
    4621
    4622 return SCIP_OKAY;
    4623}
    4624
    4625/** reformulates products of binary variables during presolving in the following way:
    4626 *
    4627 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
    4628 * Each term \f$x_i x_j\f$ is reformulated with the help of an extra (implicit integer) variable \f$z_{ij}\f$ in {0,1}:
    4629 * \f[
    4630 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
    4631 * \f]
    4632 *
    4633 * Before reformulating \f$x_i x_j\f$ in this way, it is checked whether there is a clique that contains \f$x_i\f$ and
    4634 * \f$x_j\f$. These cliques allow for a better reformulation. There are four cases:
    4635 *
    4636 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
    4637 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
    4638 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
    4639 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
    4640 *
    4641 * When a clique is used, the corresponding inequality is added as an explicit set packing or covering
    4642 * constraint to preserve model completeness, since the clique may have been derived from a constraint containing
    4643 * \f$x_i x_j\f$. For example, when \f$x_i x_j \leq 0\f$ provides the clique \f$(x_i, x_j)\f$, then the binary
    4644 * reformulation replaces \f$x_i x_j\f$ by 0 (case 1), but now \f$0 \leq 0\f$ no longer enforces \f$x_i = 0 \vee x_j = 0\f$.
    4645 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
    4646 *
    4647 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
    4648 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
    4649 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
    4650 * Such a lower sum is reformulated with only one extra variable w_i:
    4651 * \f{align}{
    4652 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
    4653 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
    4654 * \text{minact}\, x_i & \leq w_i, \\
    4655 * w_i &\leq \text{maxact}\, x_i, \\
    4656 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
    4657 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
    4658 * \f}
    4659 * We mark \f$w_i\f$ to be implicit integer if all \f$Q_{ij}\f$ are integer. After each replacement of a lower sum, it
    4660 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
    4661 * of terms are prioritized.
    4662 */
    4663static
    4665 SCIP* scip, /**< SCIP data structure */
    4666 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4667 SCIP_CONS** conss, /**< constraints */
    4668 int nconss, /**< total number of constraints */
    4669 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
    4670 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
    4671 )
    4672{
    4673 SCIP_CONSHDLRDATA* conshdlrdata;
    4674 SCIP_HASHMAP* exprmap;
    4675 SCIP_EXPRITER* it;
    4676 int c;
    4677
    4678 assert(conshdlr != NULL);
    4679
    4680 /* no nonlinear constraints or binary variables -> skip */
    4681 if( nconss == 0 || SCIPgetNBinVars(scip) + SCIPgetNImplVars(scip) == 0 )
    4682 return SCIP_OKAY;
    4683 assert(conss != NULL);
    4684
    4685 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4686 assert(conshdlrdata != NULL);
    4687
    4688 /* create expression hash map */
    4690
    4691 /* create expression iterator */
    4695
    4696 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
    4697
    4698 for( c = 0; c < nconss; ++c )
    4699 {
    4700 SCIP_CONSDATA* consdata;
    4701 SCIP_EXPR* newexpr = NULL;
    4702
    4703 assert(conss[c] != NULL);
    4704
    4705 consdata = SCIPconsGetData(conss[c]);
    4706 assert(consdata != NULL);
    4707
    4708 /* try to reformulate the root expression */
    4709 if( conshdlrdata->reformbinprodsfac > 1 )
    4710 {
    4711 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
    4712 }
    4713
    4714 /* release the root node if another expression has been found */
    4715 if( newexpr != NULL )
    4716 {
    4717 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    4718 consdata->expr = newexpr;
    4719
    4720 /* mark constraint to be not simplified anymore */
    4721 consdata->issimplified = FALSE;
    4722 }
    4723
    4724 /* replace each product of binary variables separately */
    4725 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
    4726 }
    4727
    4728 /* free memory */
    4729 SCIPhashmapFree(&exprmap);
    4730 SCIPfreeExpriter(&it);
    4731
    4732 return SCIP_OKAY;
    4733}
    4734
    4735/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
    4736 *
    4737 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
    4738 * Then scale by -1 if
    4739 * - \f$n_+ < n_-\f$, or
    4740 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
    4741 */
    4742static
    4744 SCIP* scip, /**< SCIP data structure */
    4745 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    4746 SCIP_CONS* cons, /**< nonlinear constraint */
    4747 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
    4748 )
    4749{
    4750 SCIP_CONSDATA* consdata;
    4751 int i;
    4752
    4753 assert(cons != NULL);
    4754
    4755 consdata = SCIPconsGetData(cons);
    4756 assert(consdata != NULL);
    4757
    4758 if( SCIPisExprSum(scip, consdata->expr) )
    4759 {
    4760 SCIP_Real* coefs;
    4761 SCIP_Real constant;
    4762 int nchildren;
    4763 int counter = 0;
    4764
    4765 coefs = SCIPgetCoefsExprSum(consdata->expr);
    4766 constant = SCIPgetConstantExprSum(consdata->expr);
    4767 nchildren = SCIPexprGetNChildren(consdata->expr);
    4768
    4769 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
    4770 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
    4771 {
    4772 SCIP_EXPR* expr;
    4773 expr = consdata->expr;
    4774
    4775 consdata->expr = SCIPexprGetChildren(expr)[0];
    4776 assert(!SCIPisExprSum(scip, consdata->expr));
    4777
    4778 SCIPcaptureExpr(consdata->expr);
    4779
    4780 SCIPswapReals(&consdata->lhs, &consdata->rhs);
    4781 consdata->lhs = -consdata->lhs;
    4782 consdata->rhs = -consdata->rhs;
    4783
    4784 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
    4785 *changed = TRUE;
    4786 return SCIP_OKAY;
    4787 }
    4788
    4789 /* compute n_+ - n_i */
    4790 for( i = 0; i < nchildren; ++i )
    4791 counter += coefs[i] > 0 ? 1 : -1;
    4792
    4793 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
    4794 {
    4795 SCIP_EXPR* expr;
    4796 SCIP_Real* newcoefs;
    4797
    4798 /* allocate memory */
    4799 SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
    4800
    4801 for( i = 0; i < nchildren; ++i )
    4802 newcoefs[i] = -coefs[i];
    4803
    4804 /* create a new sum expression */
    4805 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
    4806
    4807 /* replace expression in constraint data and scale sides */
    4808 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    4809 consdata->expr = expr;
    4810 SCIPswapReals(&consdata->lhs, &consdata->rhs);
    4811 consdata->lhs = -consdata->lhs;
    4812 consdata->rhs = -consdata->rhs;
    4813
    4814 /* free memory */
    4815 SCIPfreeBufferArray(scip, &newcoefs);
    4816
    4817 *changed = TRUE;
    4818 }
    4819 }
    4820
    4821 return SCIP_OKAY;
    4822}
    4823
    4824/** forbid multiaggrations of variables that appear nonlinear in constraints */
    4825static
    4827 SCIP* scip, /**< SCIP data structure */
    4828 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4829 SCIP_CONS** conss, /**< constraints */
    4830 int nconss /**< number of constraints */
    4831 )
    4832{
    4833 SCIP_EXPRITER* it;
    4834 SCIP_CONSDATA* consdata;
    4835 SCIP_EXPR* expr;
    4836 int c;
    4837
    4838 assert(scip != NULL);
    4839 assert(conshdlr != NULL);
    4840
    4841 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
    4842 return SCIP_OKAY;
    4843
    4846
    4847 for( c = 0; c < nconss; ++c )
    4848 {
    4849 consdata = SCIPconsGetData(conss[c]);
    4850 assert(consdata != NULL);
    4851
    4852 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
    4853 * i.e., skip children of sum that are variables
    4854 */
    4855 if( SCIPisExprSum(scip, consdata->expr) )
    4856 {
    4857 int i;
    4858 SCIP_EXPR* child;
    4859 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
    4860 {
    4861 child = SCIPexprGetChildren(consdata->expr)[i];
    4862
    4863 /* skip variable expression, as they correspond to a linear term */
    4864 if( SCIPisExprVar(scip, child) )
    4865 continue;
    4866
    4867 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    4868 if( SCIPisExprVar(scip, expr) )
    4869 {
    4871 }
    4872 }
    4873 }
    4874 else
    4875 {
    4876 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    4877 if( SCIPisExprVar(scip, expr) )
    4878 {
    4880 }
    4881 }
    4882 }
    4883
    4884 SCIPfreeExpriter(&it);
    4885
    4886 return SCIP_OKAY;
    4887}
    4888
    4889/** simplifies expressions and replaces common subexpressions for a set of constraints
    4890 * @todo put the constant to the constraint sides
    4891 */
    4892static
    4894 SCIP* scip, /**< SCIP data structure */
    4895 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4896 SCIP_CONS** conss, /**< constraints */
    4897 int nconss, /**< total number of constraints */
    4898 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
    4899 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
    4900 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
    4901 int* naddconss, /**< counter to add number of added constraints, or NULL */
    4902 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
    4903 )
    4904{
    4905 SCIP_CONSHDLRDATA* conshdlrdata;
    4906 SCIP_CONSDATA* consdata;
    4907 int* nlockspos;
    4908 int* nlocksneg;
    4909 SCIP_Bool havechange;
    4910 int i;
    4911
    4912 assert(scip != NULL);
    4913 assert(conshdlr != NULL);
    4914 assert(conss != NULL);
    4915 assert(nconss > 0);
    4916 assert(infeasible != NULL);
    4917
    4918 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4919 assert(conshdlrdata != NULL);
    4920
    4921 /* update number of canonicalize calls */
    4922 ++(conshdlrdata->ncanonicalizecalls);
    4923
    4924 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
    4925
    4926 *infeasible = FALSE;
    4927
    4928 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
    4929 havechange = conshdlrdata->ncanonicalizecalls == 1;
    4930
    4931 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
    4932 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
    4933
    4934 /* allocate memory for storing locks of each constraint */
    4935 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
    4936 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
    4937
    4938 /* unlock all constraints */
    4939 for( i = 0; i < nconss; ++i )
    4940 {
    4941 assert(conss[i] != NULL);
    4942
    4943 consdata = SCIPconsGetData(conss[i]);
    4944 assert(consdata != NULL);
    4945
    4946 /* remember locks */
    4947 nlockspos[i] = consdata->nlockspos;
    4948 nlocksneg[i] = consdata->nlocksneg;
    4949
    4950 /* remove locks */
    4951 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
    4952 assert(consdata->nlockspos == 0);
    4953 assert(consdata->nlocksneg == 0);
    4954 }
    4955
    4956#ifndef NDEBUG
    4957 /* check whether all locks of each expression have been removed */
    4958 for( i = 0; i < nconss; ++i )
    4959 {
    4960 SCIP_EXPR* expr;
    4961 SCIP_EXPRITER* it;
    4962
    4964
    4965 consdata = SCIPconsGetData(conss[i]);
    4966 assert(consdata != NULL);
    4967
    4969 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    4970 {
    4971 assert(expr != NULL);
    4972 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
    4973 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
    4974 }
    4975 SCIPfreeExpriter(&it);
    4976 }
    4977#endif
    4978
    4979 /* reformulate products of binary variables */
    4980 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
    4981 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
    4982 {
    4983 int tmpnaddconss = 0;
    4984 int tmpnchgcoefs = 0;
    4985
    4986 /* call this function before simplification because expressions might not be simplified after reformulating
    4987 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
    4988 */
    4989 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
    4990
    4991 /* update counters */
    4992 if( naddconss != NULL )
    4993 *naddconss += tmpnaddconss;
    4994 if( nchgcoefs != NULL )
    4995 *nchgcoefs += tmpnchgcoefs;
    4996
    4997 /* check whether at least one expression has changed */
    4998 if( tmpnaddconss + tmpnchgcoefs > 0 )
    4999 havechange = TRUE;
    5000 }
    5001
    5002 for( i = 0; i < nconss; ++i )
    5003 {
    5004 consdata = SCIPconsGetData(conss[i]);
    5005 assert(consdata != NULL);
    5006
    5007 /* call simplify for each expression */
    5008 if( !consdata->issimplified && consdata->expr != NULL )
    5009 {
    5010 SCIP_EXPR* simplified;
    5011 SCIP_Bool changed;
    5012
    5013 changed = FALSE;
    5014 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
    5015 consdata->issimplified = TRUE;
    5016
    5017 if( changed )
    5018 havechange = TRUE;
    5019
    5020 /* If root expression changed, then we need to take care updating the locks as well (the consdata is the one holding consdata->expr "as a child").
    5021 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
    5022 */
    5023 if( simplified != consdata->expr )
    5024 {
    5025 assert(changed);
    5026
    5027 /* release old expression */
    5028 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    5029
    5030 /* store simplified expression */
    5031 consdata->expr = simplified;
    5032 }
    5033 else
    5034 {
    5035 /* The simplify captures simplified in any case, also if nothing has changed.
    5036 * Therefore, we have to release it here.
    5037 */
    5038 SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
    5039 }
    5040
    5041 if( *infeasible )
    5042 break;
    5043
    5044 /* scale constraint sides */
    5045 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
    5046
    5047 if( changed )
    5048 havechange = TRUE;
    5049
    5050 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
    5051 if( SCIPisExprValue(scip, consdata->expr) )
    5052 {
    5053 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
    5054 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
    5055 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
    5056 {
    5057 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
    5058 SCIPdebugPrintCons(scip, conss[i], NULL);
    5059 *infeasible = TRUE;
    5060 break;
    5061 }
    5062 else
    5063 {
    5064 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
    5065 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
    5066 if( ndelconss != NULL )
    5067 ++*ndelconss;
    5068 havechange = TRUE;
    5069 }
    5070 }
    5071 }
    5072 }
    5073
    5074 /* replace common subexpressions */
    5075 if( havechange && !*infeasible )
    5076 {
    5077 SCIP_CONS** consssorted;
    5078 SCIP_EXPR** rootexprs;
    5079 SCIP_Bool replacedroot;
    5080
    5081 SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
    5082 for( i = 0; i < nconss; ++i )
    5083 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
    5084
    5085 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
    5086
    5087 /* update pointer to root expr in constraints, if any has changed
    5088 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
    5089 */
    5090 if( replacedroot )
    5091 for( i = 0; i < nconss; ++i )
    5092 SCIPconsGetData(conss[i])->expr = rootexprs[i];
    5093
    5094 SCIPfreeBufferArray(scip, &rootexprs);
    5095
    5096 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
    5097 * been changed after simplification; now we completely recollect all variable expression and variable events
    5098 */
    5099
    5100 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
    5101 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
    5102 */
    5103 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
    5104 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
    5105
    5106 for( i = nconss-1; i >= 0; --i )
    5107 {
    5108 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
    5109 if( SCIPconsIsDeleted(consssorted[i]) )
    5110 continue;
    5111
    5112 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
    5113 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
    5114 }
    5115 for( i = 0; i < nconss; ++i )
    5116 {
    5117 if( SCIPconsIsDeleted(consssorted[i]) )
    5118 continue;
    5119
    5120 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
    5121 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
    5122 }
    5123
    5124 SCIPfreeBufferArray(scip, &consssorted);
    5125
    5126 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
    5127 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
    5128 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
    5129 */
    5130 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
    5131 }
    5132
    5133 /* restore locks */
    5134 for( i = 0; i < nconss; ++i )
    5135 {
    5136 if( SCIPconsIsDeleted(conss[i]) )
    5137 continue;
    5138
    5139 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
    5140 }
    5141
    5142 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
    5143 * TODO can we skip this in presoltiming fast?
    5144 */
    5145 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
    5146 {
    5147 /* reset one of the number of detections counter to count only current presolving round */
    5148 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    5149 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
    5150
    5151 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
    5152 }
    5153
    5154 /* free allocated memory */
    5155 SCIPfreeBufferArray(scip, &nlocksneg);
    5156 SCIPfreeBufferArray(scip, &nlockspos);
    5157
    5158 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
    5159
    5160 return SCIP_OKAY;
    5161}
    5162
    5163/** merges constraints that have the same root expression */
    5164static
    5166 SCIP* scip, /**< SCIP data structure */
    5167 SCIP_CONS** conss, /**< constraints to process */
    5168 int nconss, /**< number of constraints */
    5169 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
    5170 )
    5171{
    5172 SCIP_HASHMAP* expr2cons;
    5173 SCIP_Bool* updatelocks;
    5174 int* nlockspos;
    5175 int* nlocksneg;
    5176 int c;
    5177
    5178 assert(success != NULL);
    5179
    5180 *success = FALSE;
    5181
    5182 /* not enough constraints available */
    5183 if( nconss <= 1 )
    5184 return SCIP_OKAY;
    5185
    5186 SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
    5187 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
    5188 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
    5189 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
    5190
    5191 for( c = 0; c < nconss; ++c )
    5192 {
    5193 SCIP_CONSDATA* consdata;
    5194
    5195 /* ignore deleted constraints */
    5196 if( SCIPconsIsDeleted(conss[c]) )
    5197 continue;
    5198
    5199 consdata = SCIPconsGetData(conss[c]);
    5200 assert(consdata != NULL);
    5201
    5202 /* add expression to the hash map if not seen so far */
    5203 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
    5204 {
    5205 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
    5206 }
    5207 else
    5208 {
    5209 SCIP_CONSDATA* imgconsdata;
    5210 int idx;
    5211
    5212 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
    5213 assert(idx >= 0 && idx < nconss);
    5214
    5215 imgconsdata = SCIPconsGetData(conss[idx]);
    5216 assert(imgconsdata != NULL);
    5217 assert(imgconsdata->expr == consdata->expr);
    5218
    5219 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
    5220 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
    5221
    5222 /* check whether locks need to be updated */
    5223 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
    5224 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
    5225 {
    5226 nlockspos[idx] = imgconsdata->nlockspos;
    5227 nlocksneg[idx] = imgconsdata->nlocksneg;
    5228 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
    5229 updatelocks[idx] = TRUE;
    5230 }
    5231
    5232 /* update constraint sides */
    5233 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
    5234 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
    5235
    5236 /* delete constraint */
    5237 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
    5238 *success = TRUE;
    5239 }
    5240 }
    5241
    5242 /* restore locks of updated constraints */
    5243 if( *success )
    5244 {
    5245 for( c = 0; c < nconss; ++c )
    5246 {
    5247 if( updatelocks[c] )
    5248 {
    5249 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
    5250 }
    5251 }
    5252 }
    5253
    5254 /* free memory */
    5255 SCIPfreeBufferArray(scip, &nlocksneg);
    5256 SCIPfreeBufferArray(scip, &nlockspos);
    5257 SCIPfreeBufferArray(scip, &updatelocks);
    5258 SCIPhashmapFree(&expr2cons);
    5259
    5260 return SCIP_OKAY;
    5261}
    5262
    5263/** interval evaluation of variables as used in redundancy check
    5264 *
    5265 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
    5266 */
    5267static
    5268SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
    5269{ /*lint --e{715}*/
    5270 SCIP_CONSHDLRDATA* conshdlrdata;
    5271 SCIP_INTERVAL interval;
    5272 SCIP_Real lb;
    5273 SCIP_Real ub;
    5274
    5275 assert(scip != NULL);
    5276 assert(var != NULL);
    5277
    5278 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
    5279 assert(conshdlrdata != NULL);
    5280
    5281 if( conshdlrdata->globalbounds )
    5282 {
    5283 lb = SCIPvarGetLbGlobal(var);
    5284 ub = SCIPvarGetUbGlobal(var);
    5285 }
    5286 else
    5287 {
    5288 lb = SCIPvarGetLbLocal(var);
    5289 ub = SCIPvarGetUbLocal(var);
    5290 }
    5291 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
    5292
    5293 /* relax variable bounds, if there are bounds and variable is not fixed
    5294 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
    5295 */
    5296 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
    5297 {
    5298 if( !SCIPisInfinity(scip, -lb) )
    5299 lb -= SCIPfeastol(scip);
    5300
    5301 if( !SCIPisInfinity(scip, ub) )
    5302 ub += SCIPfeastol(scip);
    5303 }
    5304
    5305 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
    5308 assert(lb <= ub);
    5309
    5310 SCIPintervalSetBounds(&interval, lb, ub);
    5311
    5312 return interval;
    5313}
    5314
    5315/** removes constraints that are always feasible or very simple
    5316 *
    5317 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
    5318 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
    5319 * might violate variable bounds by up to feastol, too.
    5320 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
    5321 *
    5322 * Also removes constraints of the form lhs &le; variable &le; rhs.
    5323 *
    5324 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
    5325 *
    5326 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
    5327 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
    5328 * would appear as if the constraint is redundant.
    5329 */
    5330static
    5332 SCIP* scip, /**< SCIP data structure */
    5333 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    5334 SCIP_CONS** conss, /**< constraints to propagate */
    5335 int nconss, /**< total number of constraints */
    5336 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
    5337 int* ndelconss, /**< buffer to add the number of deleted constraints */
    5338 int* nchgbds /**< buffer to add the number of variable bound tightenings */
    5339 )
    5340{
    5341 SCIP_CONSHDLRDATA* conshdlrdata;
    5342 SCIP_CONSDATA* consdata;
    5343 SCIP_INTERVAL activity;
    5344 SCIP_INTERVAL sides;
    5345 int i;
    5346
    5347 assert(scip != NULL);
    5348 assert(conshdlr != NULL);
    5349 assert(conss != NULL);
    5350 assert(nconss >= 0);
    5351 assert(cutoff != NULL);
    5352 assert(ndelconss != NULL);
    5353 assert(nchgbds != NULL);
    5354
    5355 /* no constraints to check */
    5356 if( nconss == 0 )
    5357 return SCIP_OKAY;
    5358
    5359 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5360 assert(conshdlrdata != NULL);
    5361
    5362 /* increase curboundstag and set lastvaractivitymethodchange
    5363 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
    5364 * for the redundancy check differently than for domain propagation
    5365 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
    5366 */
    5367 ++conshdlrdata->curboundstag;
    5368 assert(conshdlrdata->curboundstag > 0);
    5369 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
    5370 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
    5371 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
    5372
    5373 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
    5374
    5375 *cutoff = FALSE;
    5376 for( i = 0; i < nconss; ++i )
    5377 {
    5378 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
    5379 continue;
    5380
    5381 consdata = SCIPconsGetData(conss[i]);
    5382 assert(consdata != NULL);
    5383
    5384 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
    5385 if( SCIPisExprValue(scip, consdata->expr) )
    5386 {
    5387 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
    5388
    5389 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
    5390 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
    5391 {
    5392 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
    5393 *cutoff = TRUE;
    5394
    5395 goto TERMINATE;
    5396 }
    5397
    5398 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
    5399
    5400 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
    5401 ++*ndelconss;
    5402
    5403 continue;
    5404 }
    5405
    5406 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
    5407 if( SCIPisExprVar(scip, consdata->expr) )
    5408 {
    5409 SCIP_VAR* var;
    5410 SCIP_Bool tightened;
    5411
    5412 var = SCIPgetVarExprVar(consdata->expr);
    5413 assert(var != NULL);
    5414
    5415 SCIPdebugMsg(scip, "variable constraint <%s> can be made redundant: <%s>[%g,%g] in [%g,%g]\n", SCIPconsGetName(conss[i]), SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), consdata->lhs, consdata->rhs);
    5416
    5417 /* ensure that variable bounds are within constraint sides */
    5418 if( !SCIPisInfinity(scip, -consdata->lhs) )
    5419 {
    5420 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
    5421
    5422 if( tightened )
    5423 ++*nchgbds;
    5424
    5425 if( *cutoff )
    5426 goto TERMINATE;
    5427 }
    5428
    5429 if( !SCIPisInfinity(scip, consdata->rhs) )
    5430 {
    5431 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
    5432
    5433 if( tightened )
    5434 ++*nchgbds;
    5435
    5436 if( *cutoff )
    5437 goto TERMINATE;
    5438 }
    5439
    5440 /* delete the (now) redundant constraint locally */
    5441 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
    5442 ++*ndelconss;
    5443
    5444 continue;
    5445 }
    5446
    5447 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
    5448 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
    5449 * variable bounds by up to feastol
    5450 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
    5451 */
    5452 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
    5453 SCIPdebugPrintCons(scip, conss[i], NULL);
    5454
    5455 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
    5456 assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
    5457
    5458 /* it is unlikely that we detect infeasibility by doing forward propagation */
    5459 if( *cutoff )
    5460 {
    5461 SCIPdebugMsg(scip, " -> cutoff\n");
    5462 goto TERMINATE;
    5463 }
    5464
    5465 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
    5466 activity = SCIPexprGetActivity(consdata->expr);
    5467
    5468 /* relax sides by feastol
    5469 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
    5470 */
    5471 SCIPintervalSetBounds(&sides,
    5472 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
    5473 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
    5474
    5475 if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
    5476 {
    5477 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
    5478
    5479 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
    5480 ++*ndelconss;
    5481
    5482 continue;
    5483 }
    5484
    5485 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
    5486 }
    5487
    5488TERMINATE:
    5489 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
    5490 ++conshdlrdata->curboundstag;
    5491 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
    5492 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
    5493 conshdlrdata->intevalvar = intEvalVarBoundTightening;
    5494
    5495 return SCIP_OKAY;
    5496}
    5497
    5498/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
    5499static
    5501 SCIP* scip, /**< SCIP data structure */
    5502 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
    5503 SCIP_CONS* cons, /**< source constraint to try to convert */
    5504 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
    5505 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
    5506 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
    5507 )
    5508{
    5509 SCIP_CONSHDLRDATA* conshdlrdata;
    5510 SCIP_CONSDATA* consdata;
    5511 SCIP_CONS** upgdconss;
    5512 int upgdconsssize;
    5513 int nupgdconss_;
    5514 int i;
    5515
    5516 assert(scip != NULL);
    5517 assert(conshdlr != NULL);
    5518 assert(cons != NULL);
    5519 assert(!SCIPconsIsModifiable(cons));
    5520 assert(upgraded != NULL);
    5521 assert(nupgdconss != NULL);
    5522 assert(naddconss != NULL);
    5523
    5524 *upgraded = FALSE;
    5525
    5526 nupgdconss_ = 0;
    5527
    5528 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5529 assert(conshdlrdata != NULL);
    5530
    5531 /* if there are no upgrade methods, we can stop */
    5532 if( conshdlrdata->nconsupgrades == 0 )
    5533 return SCIP_OKAY;
    5534
    5535 upgdconsssize = 2;
    5536 SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
    5537
    5538 /* call the upgrading methods */
    5539 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
    5541
    5542 consdata = SCIPconsGetData(cons);
    5543 assert(consdata != NULL);
    5544
    5545 /* try all upgrading methods in priority order in case the upgrading step is enabled */
    5546 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
    5547 {
    5548 if( !conshdlrdata->consupgrades[i]->active )
    5549 continue;
    5550
    5551 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
    5552
    5553 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
    5554
    5555 while( nupgdconss_ < 0 )
    5556 {
    5557 /* upgrade function requires more memory: resize upgdconss and call again */
    5558 assert(-nupgdconss_ > upgdconsssize);
    5559 upgdconsssize = -nupgdconss_;
    5560 SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
    5561
    5562 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
    5563
    5564 assert(nupgdconss_ != 0);
    5565 }
    5566
    5567 if( nupgdconss_ > 0 )
    5568 {
    5569 /* got upgrade */
    5570 int j;
    5571
    5572 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
    5573
    5574 /* add the upgraded constraints to the problem and forget them */
    5575 for( j = 0; j < nupgdconss_; ++j )
    5576 {
    5577 SCIPdebugMsgPrint(scip, "\t");
    5578 SCIPdebugPrintCons(scip, upgdconss[j], NULL);
    5579
    5580 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
    5581 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
    5582 }
    5583
    5584 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
    5585 *nupgdconss += 1;
    5586 *naddconss += nupgdconss_ - 1;
    5587 *upgraded = TRUE;
    5588
    5589 /* delete upgraded constraint */
    5590 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
    5591 SCIP_CALL( SCIPdelCons(scip, cons) );
    5592
    5593 break;
    5594 }
    5595 }
    5596
    5597 SCIPfreeBufferArray(scip, &upgdconss);
    5598
    5599 return SCIP_OKAY;
    5600}
    5601
    5602/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
    5603 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
    5604 * variable bounds, and is not binary
    5605 */
    5606static
    5608 SCIP* scip, /**< SCIP data structure */
    5609 SCIP_EXPR* expr /**< variable expression */
    5610 )
    5611{
    5612 SCIP_VAR* var;
    5613 SCIP_EXPR_OWNERDATA* ownerdata;
    5614
    5615 assert(SCIPisExprVar(scip, expr));
    5616
    5617 var = SCIPgetVarExprVar(expr);
    5618 assert(var != NULL);
    5619
    5620 ownerdata = SCIPexprGetOwnerData(expr);
    5621 assert(ownerdata != NULL);
    5622
    5623 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
    5624 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
    5625 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
    5629}
    5630
    5631/** removes all variable expressions that are contained in a given expression from a hash map */
    5632static
    5634 SCIP* scip, /**< SCIP data structure */
    5635 SCIP_EXPR* expr, /**< expression */
    5636 SCIP_EXPRITER* it, /**< expression iterator */
    5637 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
    5638 )
    5639{
    5640 SCIP_EXPR* e;
    5641
    5642 for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
    5643 {
    5644 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
    5645 {
    5646 SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
    5647 }
    5648 }
    5649
    5650 return SCIP_OKAY;
    5651}
    5652
    5653/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
    5654 * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
    5655 *
    5656 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
    5657 * Otherwise, a bound disjunction constraint is added.
    5658 *
    5659 * @todo the same reduction can be applied if g(x) is not concave, but monotone in \f$x_i\f$ for g(x) &le; rhs (done in prop_dualfix?)
    5660 */
    5661static
    5663 SCIP* scip, /**< SCIP data structure */
    5664 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    5665 SCIP_CONS* cons, /**< nonlinear constraint */
    5666 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
    5667 int* naddconss, /**< pointer to store the total number of added constraints */
    5668 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
    5669 )
    5670{
    5671 SCIP_CONSHDLRDATA* conshdlrdata;
    5672 SCIP_CONSDATA* consdata;
    5673 SCIP_EXPR** singlelocked;
    5674 SCIP_HASHMAP* exprcands;
    5675 SCIP_Bool hasbounddisj;
    5676 SCIP_Bool haslhs;
    5677 SCIP_Bool hasrhs;
    5678 int nsinglelocked = 0;
    5679 int i;
    5680
    5681 assert(conshdlr != NULL);
    5682 assert(cons != NULL);
    5683 assert(nchgvartypes != NULL);
    5684 assert(naddconss != NULL);
    5685 assert(infeasible != NULL);
    5686
    5687 *nchgvartypes = 0;
    5688 *naddconss = 0;
    5689 *infeasible = FALSE;
    5690
    5691 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5692 assert(conshdlrdata != NULL);
    5693 consdata = SCIPconsGetData(cons);
    5694 assert(consdata != NULL);
    5695
    5696 /* only consider constraints with one finite side */
    5697 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
    5698 return SCIP_OKAY;
    5699
    5700 /* only consider sum expressions */
    5701 if( !SCIPisExprSum(scip, consdata->expr) )
    5702 return SCIP_OKAY;
    5703
    5704 /* remember which side is finite */
    5705 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
    5706 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
    5707
    5708 /* allocate memory */
    5709 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
    5710 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
    5711
    5712 /* check all variable expressions for single locked variables */
    5713 for( i = 0; i < consdata->nvarexprs; ++i )
    5714 {
    5715 assert(consdata->varexprs[i] != NULL);
    5716
    5717 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
    5718 {
    5719 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
    5720 singlelocked[nsinglelocked++] = consdata->varexprs[i];
    5721 }
    5722 }
    5723 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
    5724
    5725 if( nsinglelocked > 0 )
    5726 {
    5727 SCIP_EXPR** children;
    5728 SCIP_EXPRITER* it;
    5729 int nchildren;
    5730
    5731 children = SCIPexprGetChildren(consdata->expr);
    5732 nchildren = SCIPexprGetNChildren(consdata->expr);
    5733
    5734 /* create iterator */
    5738
    5739 for( i = 0; i < nchildren; ++i )
    5740 {
    5741 SCIP_EXPR* child;
    5742 SCIP_Real coef;
    5743
    5744 child = children[i];
    5745 assert(child != NULL);
    5746 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
    5747
    5748 /* ignore linear terms */
    5749 if( SCIPisExprVar(scip, child) )
    5750 continue;
    5751
    5752 /* consider products coef * prod_j f_j(x)
    5753 * - if f_j(x) is a single variable, ignore it
    5754 * - if f_j(x) = x^(2k), then keep it if product is concave when fixing all other factor;
    5755 * since x^(2k) >= 0, it suffices to check that the activity of the whole product is non-negative if haslhs or non-positive if hasrhs
    5756 * - remove all other variable expressions from exprcand
    5757 */
    5758 if( SCIPisExprProduct(scip, child) )
    5759 {
    5760 int j;
    5761 SCIP_INTERVAL productactivity;
    5762 SCIP_Bool keepevenpower;
    5763
    5764 /* activity has been ensured to be uptodate (or at least still valid) by
    5765 * call to SCIPregisterExprUsageNonlinear() in detectNlhdlrs() in canonicalize
    5766 */
    5767 productactivity = SCIPexprGetActivity(child);
    5768
    5769 /* check whether variables in even-powered factor terms can be restricted to bounds (as in SCIPisExprPower() below) */
    5770 keepevenpower = (haslhs && productactivity.inf >= 0.0) || (hasrhs && productactivity.sup <= 0.0);
    5771
    5772 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
    5773 {
    5774 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
    5775 assert(grandchild != NULL);
    5776
    5777 /* if grandchild is x^(2k), then do not remove x from exprcands */
    5778 if( keepevenpower && SCIPisExprPower(scip, grandchild) && SCIPisExprVar(scip, SCIPexprGetChildren(grandchild)[0]) )
    5779 {
    5780 SCIP_Real exponent = SCIPgetExponentExprPow(grandchild);
    5781
    5782 if( exponent > 1.0 && fmod(exponent, 2.0) == 0.0 )
    5783 continue;
    5784 }
    5785
    5786 if( !SCIPisExprVar(scip, grandchild) )
    5787 {
    5788 /* mark all variable expressions that are contained in the expression */
    5789 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
    5790 }
    5791 }
    5792 }
    5793 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
    5794 * for an integer k >= 1
    5795 */
    5796 else if( SCIPisExprPower(scip, child) )
    5797 {
    5798 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
    5799 SCIP_Real exponent = SCIPgetExponentExprPow(child);
    5800 SCIP_Bool valid;
    5801
    5802 /* check for even integral exponent */
    5803 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
    5804
    5805 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
    5806 {
    5807 /* mark all variable expressions that are contained in the expression */
    5808 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
    5809 }
    5810 }
    5811 /* all other cases cannot be handled */
    5812 else
    5813 {
    5814 /* mark all variable expressions that are contained in the expression */
    5815 SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
    5816 }
    5817 }
    5818
    5819 /* free expression iterator */
    5820 SCIPfreeExpriter(&it);
    5821 }
    5822
    5823 /* check whether the bound disjunction constraint handler is available */
    5824 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
    5825
    5826 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
    5827 for( i = 0; i < nsinglelocked; ++i )
    5828 {
    5829 /* only consider expressions that are still contained in the exprcands map */
    5830 if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
    5831 {
    5832 SCIP_CONS* newcons;
    5833 SCIP_VAR* vars[2];
    5834 SCIP_BOUNDTYPE boundtypes[2];
    5835 SCIP_Real bounds[2];
    5836 char name[SCIP_MAXSTRLEN];
    5837 SCIP_VAR* var;
    5838
    5839 var = SCIPgetVarExprVar(singlelocked[i]);
    5840 assert(var != NULL);
    5841 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
    5843
    5844 /* try to change the variable type to binary */
    5845 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
    5846 {
    5848 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
    5849 ++(*nchgvartypes);
    5850
    5851 if( *infeasible )
    5852 {
    5853 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
    5854 break;
    5855 }
    5856 }
    5857 /* add bound disjunction constraint if bounds of the variable are finite */
    5858 else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
    5859 {
    5860 vars[0] = var;
    5861 vars[1] = var;
    5862 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
    5863 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
    5864 bounds[0] = SCIPvarGetUbGlobal(var);
    5865 bounds[1] = SCIPvarGetLbGlobal(var);
    5866
    5867 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
    5868
    5869 /* create, add, and release bound disjunction constraint */
    5870 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
    5871 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
    5873 SCIP_CALL( SCIPaddCons(scip, newcons) );
    5874 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    5875 ++(*naddconss);
    5876 }
    5877 }
    5878 }
    5879
    5880 /* free memory */
    5881 SCIPfreeBufferArray(scip, &singlelocked);
    5882 SCIPhashmapFree(&exprcands);
    5883
    5884 return SCIP_OKAY;
    5885}
    5886
    5887/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
    5888static
    5890 SCIP* scip, /**< SCIP data structure */
    5891 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    5892 SCIP_CONS** conss, /**< nonlinear constraints */
    5893 int nconss, /**< total number of nonlinear constraints */
    5894 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
    5895 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
    5896 )
    5897{
    5898 int c;
    5899
    5900 assert(scip != NULL);
    5901 assert(conshdlr != NULL);
    5902 assert(conss != NULL || nconss == 0);
    5903 assert(nchgvartypes != NULL);
    5904 assert(infeasible != NULL);
    5905
    5906 *infeasible = FALSE;
    5907
    5908 /* nothing can be done on purley continuous problem */
    5910 return SCIP_OKAY;
    5911
    5912 /* no continuous var can be made implicit-integer if there are no continuous variables */
    5913 if( SCIPgetNContVars(scip) == 0 )
    5914 return SCIP_OKAY;
    5915
    5916 for( c = 0; c < nconss; ++c )
    5917 {
    5918 SCIP_CONSDATA* consdata;
    5919 SCIP_EXPR** children;
    5920 int nchildren;
    5921 SCIP_Real* coefs;
    5922 SCIP_EXPR* cand = NULL;
    5923 SCIP_Real candcoef = 0.0;
    5924 int i;
    5925 SCIP_IMPLINTTYPE impltype;
    5926
    5927 assert(conss != NULL && conss[c] != NULL);
    5928
    5929 consdata = SCIPconsGetData(conss[c]);
    5930 assert(consdata != NULL);
    5931
    5932 /* the constraint must be an equality constraint */
    5933 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
    5934 continue;
    5935
    5936 /* the root expression needs to be a sum expression */
    5937 if( !SCIPisExprSum(scip, consdata->expr) )
    5938 continue;
    5939
    5940 children = SCIPexprGetChildren(consdata->expr);
    5941 nchildren = SCIPexprGetNChildren(consdata->expr);
    5942
    5943 /* the sum expression must have at least two children
    5944 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
    5945 */
    5946 if( nchildren <= 1 )
    5947 continue;
    5948
    5949 coefs = SCIPgetCoefsExprSum(consdata->expr);
    5950
    5951 /* find first continuous variable and get value of its coefficient */
    5952 for( i = 0; i < nchildren; ++i )
    5953 {
    5954 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
    5955 continue;
    5956
    5957 candcoef = coefs[i];
    5958 assert(candcoef != 0.0);
    5959
    5960 /* lhs/rhs - constant divided by candcoef must be integral
    5961 * if not, break with cand == NULL, so give up
    5962 */
    5963 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
    5964 cand = children[i];
    5965
    5966 break;
    5967 }
    5968
    5969 /* no suitable continuous variable found */
    5970 if( cand == NULL )
    5971 continue;
    5972
    5973 impltype = SCIP_IMPLINTTYPE_STRONG;
    5974
    5975 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
    5976 for( i = 0; i < nchildren; ++i )
    5977 {
    5978 if( children[i] == cand )
    5979 continue;
    5980
    5981 impltype = MIN(impltype, SCIPexprGetIntegrality(children[i]));
    5982 /* child i must be integral */
    5983 if( impltype == SCIP_IMPLINTTYPE_NONE )
    5984 {
    5985 cand = NULL;
    5986 break;
    5987 }
    5988
    5989 /* coefficient of child i must be integral if diving by candcoef */
    5990 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
    5991 {
    5992 cand = NULL;
    5993 break;
    5994 }
    5995 }
    5996
    5997 if( cand == NULL )
    5998 continue;
    5999
    6000 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
    6002
    6003 /* change variable type */
    6004 assert(impltype != SCIP_IMPLINTTYPE_NONE);
    6005
    6006 SCIP_CALL( SCIPchgVarImplType(scip, SCIPgetVarExprVar(cand), impltype, infeasible) );
    6007 ++(*nchgvartypes);
    6008
    6009 if( *infeasible )
    6010 return SCIP_OKAY;
    6011
    6012 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
    6013 SCIPexprSetIntegrality(cand, impltype);
    6014 }
    6015
    6016 return SCIP_OKAY;
    6017}
    6018
    6019/** creates auxiliary variable for a given expression
    6020 *
    6021 * @note for a variable expression it does nothing
    6022 * @note this function can only be called in stage SCIP_STAGE_SOLVING
    6023 */
    6024static
    6026 SCIP* scip, /**< SCIP data structure */
    6027 SCIP_EXPR* expr /**< expression */
    6028 )
    6029{
    6030 SCIP_EXPR_OWNERDATA* ownerdata;
    6031 SCIP_CONSHDLRDATA* conshdlrdata;
    6032 SCIP_IMPLINTTYPE impltype;
    6033 SCIP_INTERVAL activity;
    6034 char name[SCIP_MAXSTRLEN];
    6035
    6036 assert(scip != NULL);
    6037 assert(expr != NULL);
    6038
    6039 ownerdata = SCIPexprGetOwnerData(expr);
    6040 assert(ownerdata != NULL);
    6041 assert(ownerdata->nauxvaruses > 0);
    6042
    6043 /* if we already have auxvar, then do nothing */
    6044 if( ownerdata->auxvar != NULL )
    6045 return SCIP_OKAY;
    6046
    6047 /* if expression is a variable-expression, then do nothing */
    6048 if( SCIPisExprVar(scip, expr) )
    6049 return SCIP_OKAY;
    6050
    6052 {
    6053 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
    6054 return SCIP_INVALIDCALL;
    6055 }
    6056
    6057 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    6058 assert(conshdlrdata != NULL);
    6059 assert(conshdlrdata->auxvarid >= 0);
    6060
    6061 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
    6062 * but it usually indicates a missing simplify
    6063 * if we find situations where we need to have an auxvar for a constant, then remove this assert
    6064 */
    6065 assert(!SCIPisExprValue(scip, expr));
    6066
    6067 /* create and capture auxiliary variable */
    6068 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
    6069 ++conshdlrdata->auxvarid;
    6070
    6071 /* type of auxiliary variable depends on integrality information of the expression */
    6072 impltype = SCIPexprGetIntegrality(expr);
    6073
    6074 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
    6075 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
    6076 {
    6077 activity = SCIPexprGetActivity(expr);
    6078 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
    6079 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
    6080 * and abort in debug mode only
    6081 */
    6083 {
    6084 SCIPABORT();
    6086 }
    6087 }
    6088 else
    6090
    6091 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
    6092 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
    6093 */
    6094 if( SCIPgetDepth(scip) == 0 )
    6095 {
    6096 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name,
    6097 MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0,
    6098 SCIP_VARTYPE_CONTINUOUS, impltype,
    6099 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    6100 }
    6101 else
    6102 {
    6103 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
    6104 SCIP_VARTYPE_CONTINUOUS, impltype,
    6105 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    6106 }
    6107
    6108 /* mark the auxiliary variable to be added for the relaxation only
    6109 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
    6110 * or to copy the variable to a subscip
    6111 */
    6112 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
    6113
    6114 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
    6115
    6116 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
    6117
    6118 /* add variable locks in both directions
    6119 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
    6120 * but then we need to also update the auxvars locks when the expr locks change
    6121 */
    6122 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
    6123
    6124#ifdef WITH_DEBUG_SOLUTION
    6125 if( SCIPdebugIsMainscip(scip) )
    6126 {
    6127 /* store debug solution value of auxiliary variable
    6128 * assumes that expression has been evaluated in debug solution before
    6129 */
    6130 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
    6131 }
    6132#endif
    6133
    6134 if( SCIPgetDepth(scip) > 0 )
    6135 {
    6136 /* initialize local bounds to (locally valid) activity */
    6137 SCIP_Bool cutoff;
    6138 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
    6139 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
    6140 }
    6141
    6142 return SCIP_OKAY;
    6143}
    6144
    6145/** initializes separation for constraint
    6146 *
    6147 * - ensures that activities are up to date in all expressions
    6148 * - creates auxiliary variables where required
    6149 * - calls propExprDomains() to possibly tighten auxvar bounds
    6150 * - calls separation initialization callback of nlhdlrs
    6151 */
    6152static
    6154 SCIP* scip, /**< SCIP data structure */
    6155 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    6156 SCIP_CONS** conss, /**< constraints */
    6157 int nconss, /**< number of constraints */
    6158 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
    6159 )
    6160{
    6161 SCIP_CONSDATA* consdata;
    6162 SCIP_CONSHDLRDATA* conshdlrdata;
    6163 SCIP_EXPRITER* it;
    6164 SCIP_EXPR* expr;
    6165 SCIP_RESULT result;
    6166 SCIP_VAR* auxvar;
    6167 int nreductions = 0;
    6168 int c, e;
    6169
    6170 assert(scip != NULL);
    6171 assert(conshdlr != NULL);
    6172 assert(conss != NULL || nconss == 0);
    6173 assert(nconss >= 0);
    6174 assert(infeasible != NULL);
    6175
    6176 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6177 assert(conshdlrdata != NULL);
    6178
    6179 /* start with new propbounds (just to be sure, should not be needed) */
    6180 ++conshdlrdata->curpropboundstag;
    6181
    6184
    6185 /* first ensure activities are up to date and create auxvars */
    6186 *infeasible = FALSE;
    6187 for( c = 0; c < nconss; ++c )
    6188 {
    6189 assert(conss != NULL);
    6190 assert(conss[c] != NULL);
    6191
    6192 consdata = SCIPconsGetData(conss[c]);
    6193 assert(consdata != NULL);
    6194 assert(consdata->expr != NULL);
    6195
    6196#ifdef WITH_DEBUG_SOLUTION
    6197 if( SCIPdebugIsMainscip(scip) )
    6198 {
    6199 SCIP_SOL* debugsol;
    6200
    6201 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
    6202
    6203 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
    6204 {
    6205 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
    6206 * in createAuxVar()
    6207 */
    6208 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
    6209 }
    6210 }
    6211#endif
    6212
    6213 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
    6214 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
    6215
    6216 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    6217 {
    6218 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
    6219 {
    6220 SCIP_CALL( createAuxVar(scip, expr) );
    6221 }
    6222 }
    6223
    6224 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
    6225 if( auxvar != NULL )
    6226 {
    6227 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
    6228 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
    6229 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
    6230 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
    6231 if( *infeasible )
    6232 {
    6233 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
    6234 break;
    6235 }
    6236
    6237 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
    6238 if( *infeasible )
    6239 {
    6240 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
    6241 break;
    6242 }
    6243 }
    6244 }
    6245
    6246 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
    6247 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
    6248 * (e.g., log(x*y), which becomes log(w), w=x*y
    6249 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
    6250 */
    6251 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
    6252 if( result == SCIP_CUTOFF )
    6253 *infeasible = TRUE;
    6254
    6255 /* now call initsepa of nlhdlrs
    6256 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
    6257 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
    6258 */
    6260 for( c = 0; c < nconss && !*infeasible; ++c )
    6261 {
    6262 assert(conss != NULL);
    6263 assert(conss[c] != NULL);
    6264
    6265 consdata = SCIPconsGetData(conss[c]);
    6266 assert(consdata != NULL);
    6267 assert(consdata->expr != NULL);
    6268
    6269 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
    6270 {
    6271 SCIP_EXPR_OWNERDATA* ownerdata;
    6272
    6273 ownerdata = SCIPexprGetOwnerData(expr);
    6274 assert(ownerdata != NULL);
    6275
    6276 if( ownerdata->nauxvaruses == 0 )
    6277 continue;
    6278
    6279 for( e = 0; e < ownerdata->nenfos; ++e )
    6280 {
    6281 SCIP_NLHDLR* nlhdlr;
    6282 SCIP_Bool underestimate;
    6283 SCIP_Bool overestimate;
    6284 assert(ownerdata->enfos[e] != NULL);
    6285
    6286 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
    6287 * which participated in a previous initSepa() call
    6288 */
    6289 if( ownerdata->enfos[e]->issepainit )
    6290 continue;
    6291
    6292 /* only call initsepa if it will actually separate */
    6293 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
    6294 continue;
    6295
    6296 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    6297 assert(nlhdlr != NULL);
    6298
    6299 /* only init sepa if there is an initsepa callback */
    6300 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
    6301 continue;
    6302
    6303 /* check whether expression needs to be under- or overestimated */
    6304 overestimate = ownerdata->nlocksneg > 0;
    6305 underestimate = ownerdata->nlockspos > 0;
    6306 assert(underestimate || overestimate);
    6307
    6308 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
    6309
    6310 /* call the separation initialization callback of the nonlinear handler */
    6311 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
    6312 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
    6313 ownerdata->enfos[e]->issepainit = TRUE;
    6314
    6315 if( *infeasible )
    6316 {
    6317 /* stop everything if we detected infeasibility */
    6318 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
    6319 break;
    6320 }
    6321 }
    6322 }
    6323 }
    6324
    6325 SCIPfreeExpriter(&it);
    6326
    6327 return SCIP_OKAY;
    6328}
    6329
    6330/** returns whether we are ok to branch on auxiliary variables
    6331 *
    6332 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
    6333 */
    6334static
    6336 SCIP* scip, /**< SCIP data structure */
    6337 SCIP_CONSHDLR* conshdlr /**< constraint handler */
    6338 )
    6339{
    6340 SCIP_CONSHDLRDATA* conshdlrdata;
    6341
    6342 assert(conshdlr != NULL);
    6343
    6344 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6345 assert(conshdlrdata != NULL);
    6346
    6347 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
    6348}
    6349
    6350/** gets weight of variable when splitting violation score onto several variables in an expression */
    6351static
    6353 SCIP* scip, /**< SCIP data structure */
    6354 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
    6355 SCIP_VAR* var, /**< variable */
    6356 SCIP_SOL* sol /**< current solution */
    6357 )
    6358{
    6359 SCIP_CONSHDLRDATA* conshdlrdata;
    6360
    6361 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6362 assert(conshdlrdata != NULL);
    6363
    6364 switch( conshdlrdata->branchviolsplit )
    6365 {
    6366 case 'u' : /* uniform: everyone gets the same score */
    6367 return 1.0;
    6368
    6369 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
    6370 {
    6371 SCIP_Real weight;
    6372 weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
    6373 return MAX(0.05, weight);
    6374 }
    6375
    6376 case 'd' : /* domain width */
    6377 return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
    6378
    6379 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
    6380 {
    6381 SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
    6382 assert(width > 0.0);
    6383 if( width > 10.0 )
    6384 return 10.0*log10(width);
    6385 if( width < 0.1 )
    6386 return 0.1/(-log10(width));
    6387 return width;
    6388 }
    6389
    6390 default :
    6391 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
    6392 SCIPABORT();
    6393 return SCIP_INVALID;
    6394 }
    6395}
    6396
    6397/** adds violation-branching score to a set of expressions, thereby distributing the score
    6398 *
    6399 * Each expression must either be a variable expression or have an aux-variable.
    6400 *
    6401 * If unbounded variables are present, each unbounded var gets an even score.
    6402 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
    6403 */
    6404static
    6406 SCIP* scip, /**< SCIP data structure */
    6407 SCIP_EXPR** exprs, /**< expressions where to add branching score */
    6408 int nexprs, /**< number of expressions */
    6409 SCIP_Real violscore, /**< violation-branching score to add to expression */
    6410 SCIP_SOL* sol, /**< current solution */
    6411 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
    6412 )
    6413{
    6414 SCIP_CONSHDLR* conshdlr;
    6415 SCIP_VAR* var;
    6416 SCIP_Real weight;
    6417 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
    6418 int nunbounded = 0; /* number of candidates with unbounded domain */
    6419 int i;
    6420
    6421 assert(exprs != NULL);
    6422 assert(nexprs >= 0);
    6423 assert(success != NULL);
    6424
    6425 if( nexprs == 1 )
    6426 {
    6427 SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
    6428 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
    6430 *success = TRUE;
    6431 return;
    6432 }
    6433
    6434 if( nexprs == 0 )
    6435 {
    6436 *success = FALSE;
    6437 return;
    6438 }
    6439
    6440 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
    6441
    6442 for( i = 0; i < nexprs; ++i )
    6443 {
    6444 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
    6445 assert(var != NULL);
    6446
    6448 ++nunbounded;
    6449 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
    6450 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
    6451 }
    6452
    6453 *success = FALSE;
    6454 for( i = 0; i < nexprs; ++i )
    6455 {
    6456 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
    6457 assert(var != NULL);
    6458
    6459 if( nunbounded > 0 )
    6460 {
    6462 {
    6463 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
    6464 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
    6465 100.0/nunbounded, violscore,
    6467 *success = TRUE;
    6468 }
    6469 }
    6470 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
    6471 {
    6472 assert(weightsum > 0.0);
    6473
    6474 weight = getViolSplitWeight(scip, conshdlr, var, sol);
    6475 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
    6476 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
    6477 100*weight / weightsum, violscore,
    6479 *success = TRUE;
    6480 }
    6481 else
    6482 {
    6483 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
    6485 }
    6486 }
    6487}
    6488
    6489/** adds violation-branching score to children of expression for given auxiliary variables
    6490 *
    6491 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
    6492 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
    6493 *
    6494 * @note This method may modify the given auxvars array by means of sorting.
    6495 */
    6496static
    6498 SCIP* scip, /**< SCIP data structure */
    6499 SCIP_EXPR* expr, /**< expression where to start searching */
    6500 SCIP_Real violscore, /**< violation score to add to expression */
    6501 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
    6502 int nauxvars, /**< number of auxiliary variables */
    6503 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
    6504 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
    6505 )
    6506{
    6507 SCIP_EXPRITER* it;
    6508 SCIP_VAR* auxvar;
    6509 SCIP_EXPR** exprs;
    6510 int nexprs;
    6511 int pos;
    6512
    6513 assert(scip != NULL);
    6514 assert(expr != NULL);
    6515 assert(auxvars != NULL);
    6516 assert(success != NULL);
    6517
    6518 /* sort variables to make lookup below faster */
    6519 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
    6520
    6523
    6524 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
    6525 nexprs = 0;
    6526
    6527 for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    6528 {
    6529 auxvar = SCIPgetExprAuxVarNonlinear(expr);
    6530 if( auxvar == NULL )
    6531 continue;
    6532
    6533 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
    6534 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
    6535 {
    6536 assert(auxvars[pos] == auxvar);
    6537
    6538 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
    6539 exprs[nexprs++] = expr;
    6540
    6541 if( nexprs == nauxvars )
    6542 break;
    6543 }
    6544 }
    6545
    6546 SCIPfreeExpriter(&it);
    6547
    6548 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
    6549
    6550 SCIPfreeBufferArray(scip, &exprs);
    6551
    6552 return SCIP_OKAY;
    6553}
    6554
    6555/** registers all unfixed variables in violated constraints as branching candidates */
    6556static
    6558 SCIP* scip, /**< SCIP data structure */
    6559 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    6560 SCIP_CONS** conss, /**< constraints */
    6561 int nconss, /**< number of constraints */
    6562 int* nnotify /**< counter for number of notifications performed */
    6563 )
    6564{
    6565 SCIP_CONSDATA* consdata;
    6566 SCIP_VAR* var;
    6567 int c;
    6568 int i;
    6569
    6570 assert(conshdlr != NULL);
    6571 assert(conss != NULL || nconss == 0);
    6572 assert(nnotify != NULL);
    6573
    6574 *nnotify = 0;
    6575
    6576 for( c = 0; c < nconss; ++c )
    6577 {
    6578 assert(conss != NULL && conss[c] != NULL);
    6579
    6580 consdata = SCIPconsGetData(conss[c]);
    6581 assert(consdata != NULL);
    6582
    6583 /* consider only violated constraints */
    6584 if( !isConsViolated(scip, conss[c]) )
    6585 continue;
    6586
    6587 /* register all variables that have not been fixed yet */
    6588 assert(consdata->varexprs != NULL);
    6589 for( i = 0; i < consdata->nvarexprs; ++i )
    6590 {
    6591 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    6592 assert(var != NULL);
    6593
    6595 {
    6597 ++(*nnotify);
    6598 }
    6599 }
    6600 }
    6601
    6602 return SCIP_OKAY;
    6603}
    6604
    6605/** registers all variables in violated constraints with branching scores as external branching candidates */
    6606static
    6608 SCIP* scip, /**< SCIP data structure */
    6609 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    6610 SCIP_CONS** conss, /**< constraints */
    6611 int nconss, /**< number of constraints */
    6612 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
    6613 )
    6614{
    6615 SCIP_CONSDATA* consdata;
    6616 SCIP_EXPRITER* it = NULL;
    6617 int c;
    6618
    6619 assert(conshdlr != NULL);
    6620 assert(success != NULL);
    6621
    6622 *success = FALSE;
    6623
    6624 if( branchAuxNonlinear(scip, conshdlr) )
    6625 {
    6628 }
    6629
    6630 /* register external branching candidates */
    6631 for( c = 0; c < nconss; ++c )
    6632 {
    6633 assert(conss != NULL && conss[c] != NULL);
    6634
    6635 consdata = SCIPconsGetData(conss[c]);
    6636 assert(consdata != NULL);
    6637 assert(consdata->varexprs != NULL);
    6638
    6639 /* consider only violated constraints */
    6640 if( !isConsViolated(scip, conss[c]) )
    6641 continue;
    6642
    6643 if( !branchAuxNonlinear(scip, conshdlr) )
    6644 {
    6645 int i;
    6646
    6647 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
    6648 * only, so we can loop over variable expressions
    6649 */
    6650 for( i = 0; i < consdata->nvarexprs; ++i )
    6651 {
    6652 SCIP_Real violscore;
    6653 SCIP_Real lb;
    6654 SCIP_Real ub;
    6655 SCIP_VAR* var;
    6656
    6657 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
    6658
    6659 /* skip variable expressions that do not have a violation score */
    6660 if( violscore == 0.0 )
    6661 continue;
    6662
    6663 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    6664 assert(var != NULL);
    6665
    6666 lb = SCIPvarGetLbLocal(var);
    6667 ub = SCIPvarGetUbLocal(var);
    6668
    6669 /* consider variable for branching if it has not been fixed yet */
    6670 if( !SCIPisEQ(scip, lb, ub) )
    6671 {
    6672 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
    6674 *success = TRUE;
    6675 }
    6676 else
    6677 {
    6678 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
    6679 }
    6680
    6681 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
    6682 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
    6683 */
    6684 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
    6685 }
    6686 }
    6687 else
    6688 {
    6689 SCIP_EXPR* expr;
    6690 SCIP_VAR* var;
    6691 SCIP_Real lb;
    6692 SCIP_Real ub;
    6693 SCIP_Real violscore;
    6694
    6695 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    6696 {
    6697 violscore = SCIPgetExprViolScoreNonlinear(expr);
    6698 if( violscore == 0.0 )
    6699 continue;
    6700
    6701 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
    6702 * variable, so this expression should either be an original variable or have an auxiliary variable
    6703 */
    6704 var = SCIPgetExprAuxVarNonlinear(expr);
    6705 assert(var != NULL);
    6706
    6707 lb = SCIPvarGetLbLocal(var);
    6708 ub = SCIPvarGetUbLocal(var);
    6709
    6710 /* consider variable for branching if it has not been fixed yet */
    6711 if( !SCIPisEQ(scip, lb, ub) )
    6712 {
    6713 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
    6714
    6716 *success = TRUE;
    6717 }
    6718 else
    6719 {
    6720 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
    6721 }
    6722 }
    6723 }
    6724 }
    6725
    6726 if( it != NULL )
    6727 SCIPfreeExpriter(&it);
    6728
    6729 return SCIP_OKAY;
    6730}
    6731
    6732/** collect branching candidates from violated constraints
    6733 *
    6734 * Fills array with expressions that serve as branching candidates.
    6735 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
    6736 * branching candidate.
    6737 *
    6738 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
    6739 * through variable-expressions only.
    6740 */
    6741static
    6743 SCIP* scip, /**< SCIP data structure */
    6744 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6745 SCIP_CONS** conss, /**< constraints to process */
    6746 int nconss, /**< number of constraints */
    6747 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
    6748 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    6749 SCIP_Longint soltag, /**< tag of solution */
    6750 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
    6751 int* ncands /**< number of candidates found */
    6752 )
    6753{
    6754 SCIP_CONSHDLRDATA* conshdlrdata;
    6755 SCIP_CONSDATA* consdata;
    6756 SCIP_EXPRITER* it = NULL;
    6757 int c;
    6758 int attempt;
    6759 SCIP_VAR* var;
    6760
    6761 assert(scip != NULL);
    6762 assert(conshdlr != NULL);
    6763 assert(cands != NULL);
    6764 assert(ncands != NULL);
    6765
    6766 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6767 assert(conshdlrdata != NULL);
    6768
    6769 if( branchAuxNonlinear(scip, conshdlr) )
    6770 {
    6773 }
    6774
    6775 *ncands = 0;
    6776 for( attempt = 0; attempt < 2; ++attempt )
    6777 {
    6778 /* collect branching candidates from violated constraints
    6779 * in the first attempt, consider only constraints with large violation
    6780 * in the second attempt, consider all remaining violated constraints
    6781 */
    6782 for( c = 0; c < nconss; ++c )
    6783 {
    6784 SCIP_Real consviol;
    6785
    6786 assert(conss != NULL && conss[c] != NULL);
    6787
    6788 /* consider only violated constraints */
    6789 if( !isConsViolated(scip, conss[c]) )
    6790 continue;
    6791
    6792 consdata = SCIPconsGetData(conss[c]);
    6793 assert(consdata != NULL);
    6794 assert(consdata->varexprs != NULL);
    6795
    6796 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
    6797
    6798 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
    6799 continue;
    6800 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
    6801 continue;
    6802
    6803 if( !branchAuxNonlinear(scip, conshdlr) )
    6804 {
    6805 int i;
    6806
    6807 /* if not branching on auxvars, then violation-branching scores will be available for original variables
    6808 * only, so we can loop over variable expressions
    6809 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
    6810 * variable, therefore we invalidate the score of a variable after processing it.
    6811 */
    6812 for( i = 0; i < consdata->nvarexprs; ++i )
    6813 {
    6814 SCIP_Real lb;
    6815 SCIP_Real ub;
    6816
    6817 /* skip variable expressions that do not have a valid violation score */
    6818 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
    6819 continue;
    6820
    6821 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    6822 assert(var != NULL);
    6823
    6824 lb = SCIPvarGetLbLocal(var);
    6825 ub = SCIPvarGetUbLocal(var);
    6826
    6827 /* skip already fixed variable */
    6828 if( SCIPisEQ(scip, lb, ub) )
    6829 {
    6830 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
    6831 continue;
    6832 }
    6833
    6834 assert(*ncands + 1 < SCIPgetNVars(scip));
    6835 cands[*ncands].expr = consdata->varexprs[i];
    6836 cands[*ncands].var = var;
    6837 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
    6838 cands[*ncands].fractionality = 0.0;
    6839 ++(*ncands);
    6840
    6841 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
    6842 * several times as external branching candidate */
    6843 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
    6844 }
    6845 }
    6846 else
    6847 {
    6848 SCIP_EXPR* expr;
    6849 SCIP_Real lb;
    6850 SCIP_Real ub;
    6851
    6852 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    6853 {
    6854 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
    6855 continue;
    6856
    6857 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
    6858 * variables, so this expression should either be an original variable or have an auxiliary variable
    6859 */
    6860 var = SCIPgetExprAuxVarNonlinear(expr);
    6861 assert(var != NULL);
    6862
    6863 lb = SCIPvarGetLbLocal(var);
    6864 ub = SCIPvarGetUbLocal(var);
    6865
    6866 /* skip already fixed variable */
    6867 if( SCIPisEQ(scip, lb, ub) )
    6868 {
    6869 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
    6870 continue;
    6871 }
    6872
    6873 assert(*ncands + 1 < SCIPgetNVars(scip));
    6874 cands[*ncands].expr = expr;
    6875 cands[*ncands].var = var;
    6876 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
    6877 cands[*ncands].fractionality = 0.0;
    6878 ++(*ncands);
    6879 }
    6880 }
    6881 }
    6882
    6883 /* if we have branching candidates, then we don't need another attempt */
    6884 if( *ncands > 0 )
    6885 break;
    6886 }
    6887
    6888 if( it != NULL )
    6889 SCIPfreeExpriter(&it);
    6890
    6891 return SCIP_OKAY;
    6892}
    6893
    6894/** computes a branching score for a variable that reflects how important branching on this variable would be for
    6895 * improving the dual bound from the LP relaxation
    6896 *
    6897 * Assume the Lagrangian for the current LP is something of the form
    6898 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
    6899 * where x are the original variables, z the auxiliary variables,
    6900 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
    6901 *
    6902 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
    6903 * If we could have used not only an estimator, but the actual function f(x), then this would
    6904 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
    6905 * Using a lot of handwaving, we claim that
    6906 * lambda_i * (f(x) - a_i'x + b_i)
    6907 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
    6908 * If an estimator depended on local bounds, then it could be improved by branching.
    6909 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
    6910 *
    6911 * To score a variable, we then sum the values lambda_i * (f(x) - a_i'x + b_i) for all rows in which the variable appears.
    6912 * To scale, we divide by the LP objective value (if >1).
    6913 *
    6914 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
    6915 * these are affected by the bounds on original variables indirectly (through forward-propagation)
    6916 *
    6917 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
    6918 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
    6919 * would also be branching candidates
    6920 */
    6921static
    6923 SCIP* scip, /**< SCIP data structure */
    6924 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    6925 SCIP_VAR* var /**< variable */
    6926 )
    6927{
    6928 SCIP_COL* col;
    6929 SCIP_ROW** rows;
    6930 int nrows;
    6931 int r;
    6932 SCIP_Real dualscore;
    6933
    6934 assert(scip != NULL);
    6935 assert(conshdlr != NULL);
    6936 assert(var != NULL);
    6937
    6938 /* if LP not solved, then the dual branching score is not available */
    6940 return 0.0;
    6941
    6942 /* if var is not in the LP, then the dual branching score is not available */
    6944 return 0.0;
    6945
    6946 col = SCIPvarGetCol(var);
    6947 assert(col != NULL);
    6948
    6949 if( !SCIPcolIsInLP(col) )
    6950 return 0.0;
    6951
    6952 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
    6953 rows = SCIPcolGetRows(col);
    6954
    6955 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
    6956
    6957 /* aggregate duals from all rows from consexpr with non-zero dual
    6958 * TODO: this is a quick-and-dirty implementation, and not used by default
    6959 * in the long run, this should be either removed or replaced by a proper implementation
    6960 */
    6961 dualscore = 0.0;
    6962 for( r = 0; r < nrows; ++r )
    6963 {
    6964 SCIP_Real estimategap;
    6965 const char* estimategapstr;
    6966
    6967 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
    6968 * these would typically be local, unless they are created at the root node
    6969 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
    6970 if( !SCIProwIsLocal(rows[r]) )
    6971 continue;
    6972 */
    6973 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
    6974 continue;
    6975 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
    6976 continue;
    6977
    6978 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
    6979 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
    6980 continue;
    6981 estimategap = atof(estimategapstr + 13);
    6982 assert(estimategap >= 0.0);
    6983 if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
    6984 estimategap = SCIPgetHugeValue(scip);
    6985
    6986 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
    6987 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
    6988
    6989 dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
    6990 }
    6991
    6992 /* divide by optimal value of LP for scaling */
    6993 dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
    6994
    6995 return dualscore;
    6996}
    6997
    6998/** computes branching scores (including weighted score) for a set of candidates
    6999 *
    7000 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
    7001 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
    7002 *
    7003 * For each score, compute the maximum over all candidates.
    7004 *
    7005 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
    7006 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
    7007 * score of all candidates.
    7008 * Further divide by the sum of all weights where a score was available (even if the score was 0).
    7009 *
    7010 * For example:
    7011 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
    7012 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
    7013 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
    7014 * - Then the weighted scores for x will be (2.0 * 10.0/12.0 + 3.0 * 5.0/5.0) / (2.0 + 3.0) = 0.9333.
    7015 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
    7016 */
    7017static
    7019 SCIP* scip, /**< SCIP data structure */
    7020 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7021 BRANCHCAND* cands, /**< branching candidates */
    7022 int ncands, /**< number of candidates */
    7023 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
    7024 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
    7025 )
    7026{
    7027 SCIP_CONSHDLRDATA* conshdlrdata;
    7028 BRANCHCAND maxscore;
    7029 int c;
    7030
    7031 assert(scip != NULL);
    7032 assert(conshdlr != NULL);
    7033 assert(cands != NULL);
    7034 assert(ncands > 0);
    7035
    7036 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7037 assert(conshdlrdata != NULL);
    7038
    7039 /* initialize counts to 0 */
    7040 memset(&maxscore, 0, sizeof(BRANCHCAND));
    7041
    7042 for( c = 0; c < ncands; ++c )
    7043 {
    7044 if( conshdlrdata->branchviolweight > 0.0 )
    7045 {
    7046 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
    7047 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
    7048 }
    7049
    7050 if( conshdlrdata->branchfracweight > 0.0 && SCIPvarIsNonimpliedIntegral(cands[c].var) )
    7051 {
    7052 /* when collecting for branching on fractionality (cands[c].expr == NULL), only fractional integer variables
    7053 * should appear as candidates here and their fractionality should have been recorded in branchingIntegralOrNonlinear
    7054 */
    7055 assert(cands[c].expr != NULL || cands[c].fractionality > 0.0);
    7056
    7057 if( considerfracnl && cands[c].fractionality == 0.0 )
    7058 {
    7059 /* for an integer variable that is subject to spatial branching, we also record the fractionality (but separately from auxviol)
    7060 * if considerfracnl is TRUE; this way, we can give preference to fractional integer nonlinear variables
    7061 */
    7062 SCIP_Real solval;
    7063 SCIP_Real rounded;
    7064
    7065 solval = SCIPgetSolVal(scip, sol, cands[c].var);
    7066 rounded = SCIPround(scip, solval);
    7067
    7068 cands[c].fractionality = REALABS(solval - rounded);
    7069 }
    7070
    7071 maxscore.fractionality = MAX(cands[c].fractionality, maxscore.fractionality);
    7072 }
    7073 else
    7074 cands[c].fractionality = 0.0;
    7075
    7076 if( conshdlrdata->branchdomainweight > 0.0 && cands[c].expr != NULL )
    7077 {
    7078 SCIP_Real domainwidth;
    7079 SCIP_VAR* var;
    7080
    7081 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
    7082 assert(var != NULL);
    7083
    7084 /* get domain width, taking infinity at 1e20 on purpose */
    7085 domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
    7086
    7087 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
    7088 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
    7089 * the idea is to penalize very large and very small domains
    7090 */
    7091 if( domainwidth >= 1.0 )
    7092 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
    7093 else
    7094 cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
    7095
    7096 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
    7097 }
    7098 else
    7099 cands[c].domain = 0.0;
    7100
    7101 if( conshdlrdata->branchdualweight > 0.0 && cands[c].expr != NULL )
    7102 {
    7103 SCIP_VAR* var;
    7104
    7105 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
    7106 assert(var != NULL);
    7107
    7108 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
    7109 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
    7110 }
    7111 else
    7112 cands[c].dual = 0.0;
    7113
    7114 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
    7115 {
    7116 SCIP_VAR* var;
    7117
    7118 var = cands[c].var;
    7119 assert(var != NULL);
    7120
    7121 if( cands[c].expr != NULL )
    7122 {
    7124 cands[c].pscost = SCIP_INVALID;
    7125 else
    7126 {
    7127 SCIP_Real brpoint;
    7128 SCIP_Real pscostdown;
    7129 SCIP_Real pscostup;
    7130 char strategy;
    7131
    7132 /* decide how to compute pseudo-cost scores
    7133 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
    7134 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
    7135 */
    7136 if( !SCIPvarIsIntegral(var) )
    7137 strategy = conshdlrdata->branchpscostupdatestrategy;
    7138 else
    7139 strategy = 'l';
    7140
    7141 brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
    7142
    7143 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
    7144 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
    7145 * For here, I use a simple #counts >= branchpscostreliable.
    7146 * TODO use SCIPgetVarPseudocostCount() instead?
    7147 */
    7148 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
    7149 {
    7150 switch( strategy )
    7151 {
    7152 case 's' :
    7153 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
    7154 break;
    7155 case 'd' :
    7156 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
    7157 break;
    7158 case 'l' :
    7159 if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
    7160 pscostdown = SCIP_INVALID;
    7161 else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
    7162 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
    7163 else
    7164 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, sol, var) - SCIPadjustedVarUb(scip, var, brpoint)));
    7165 break;
    7166 default :
    7167 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
    7168 pscostdown = SCIP_INVALID;
    7169 }
    7170 }
    7171 else
    7172 pscostdown = SCIP_INVALID;
    7173
    7174 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
    7175 {
    7176 switch( strategy )
    7177 {
    7178 case 's' :
    7179 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
    7180 break;
    7181 case 'd' :
    7182 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
    7183 break;
    7184 case 'l' :
    7185 if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
    7186 pscostup = SCIP_INVALID;
    7187 else if( SCIPgetSolVal(scip, sol, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
    7188 pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
    7189 else
    7190 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, sol, var) );
    7191 break;
    7192 default :
    7193 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
    7194 pscostup = SCIP_INVALID;
    7195 }
    7196 }
    7197 else
    7198 pscostup = SCIP_INVALID;
    7199
    7200 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
    7201 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
    7202 */
    7203 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
    7204 cands[c].pscost = SCIP_INVALID;
    7205 else if( pscostdown == SCIP_INVALID )
    7206 cands[c].pscost = pscostup;
    7207 else if( pscostup == SCIP_INVALID )
    7208 cands[c].pscost = pscostdown;
    7209 else
    7210 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
    7211 }
    7212 }
    7213 else
    7214 {
    7215 SCIP_Real pscostdown;
    7216 SCIP_Real pscostup;
    7217 SCIP_Real solval;
    7218
    7219 solval = SCIPgetSolVal(scip, sol, cands[c].var);
    7220
    7221 /* the calculation for pscostdown/up follows SCIPgetVarPseudocostScore(),
    7222 * i.e., set solvaldelta to the (negated) difference between variable value and rounded down value for pscostdown
    7223 * and different between variable value and rounded up value for pscostup
    7224 */
    7225 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
    7226 pscostdown = SCIPgetVarPseudocostVal(scip, var, SCIPfeasCeil(scip, solval - 1.0) - solval);
    7227 else
    7228 pscostdown = SCIP_INVALID;
    7229
    7230 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
    7231 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPfeasFloor(scip, solval + 1.0) - solval);
    7232 else
    7233 pscostup = SCIP_INVALID;
    7234
    7235 /* TODO see above for nonlinear variable case */
    7236 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
    7237 cands[c].pscost = SCIP_INVALID;
    7238 else if( pscostdown == SCIP_INVALID )
    7239 cands[c].pscost = pscostup;
    7240 else if( pscostup == SCIP_INVALID )
    7241 cands[c].pscost = pscostdown;
    7242 else
    7243 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
    7244 }
    7245
    7246 if( cands[c].pscost != SCIP_INVALID )
    7247 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
    7248 }
    7249 else
    7250 cands[c].pscost = SCIP_INVALID;
    7251
    7252 if( conshdlrdata->branchvartypeweight > 0.0 )
    7253 {
    7254 switch( SCIPvarGetType(cands[c].var) )
    7255 {
    7257 cands[c].vartype = 1.0;
    7258 break;
    7260 cands[c].vartype = 0.1;
    7261 break;
    7263 if( SCIPvarIsImpliedIntegral(cands[c].var) )
    7264 cands[c].vartype = 0.01;
    7265 else
    7266 cands[c].vartype = 0.0;
    7267 break;
    7268 default:
    7269 SCIPerrorMessage("invalid variable type\n");
    7270 SCIPABORT();
    7271 return; /*lint !e527*/
    7272 } /*lint !e788*/
    7273
    7274 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
    7275 }
    7276 }
    7277
    7278 /* now compute a weighted score for each candidate from the single scores
    7279 * the single scores are scaled to be in [0,1] for this
    7280 */
    7281 for( c = 0; c < ncands; ++c )
    7282 {
    7283 SCIP_Real weightsum;
    7284
    7285 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(cands[c].var), SCIPvarGetLbLocal(cands[c].var), SCIPvarGetUbLocal(cands[c].var)); )
    7286
    7287 cands[c].weighted = 0.0;
    7288 weightsum = 0.0;
    7289
    7290 if( maxscore.auxviol > 0.0 )
    7291 {
    7292 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
    7293 weightsum += conshdlrdata->branchviolweight;
    7294
    7295 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
    7296 }
    7297
    7298 if( maxscore.fractionality > 0.0 )
    7299 {
    7300 cands[c].weighted += conshdlrdata->branchfracweight * cands[c].fractionality / maxscore.fractionality;
    7301 weightsum += conshdlrdata->branchfracweight;
    7302
    7303 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(frac)", conshdlrdata->branchfracweight, cands[c].fractionality / maxscore.fractionality); )
    7304 }
    7305
    7306 if( maxscore.domain > 0.0 )
    7307 {
    7308 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
    7309 weightsum += conshdlrdata->branchdomainweight;
    7310
    7311 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
    7312 }
    7313
    7314 if( maxscore.dual > 0.0 )
    7315 {
    7316 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
    7317 weightsum += conshdlrdata->branchdualweight;
    7318
    7319 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
    7320 }
    7321
    7322 if( maxscore.pscost > 0.0 )
    7323 {
    7324 /* use pseudo-costs only if available */
    7325 if( cands[c].pscost != SCIP_INVALID )
    7326 {
    7327 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
    7328 weightsum += conshdlrdata->branchpscostweight;
    7329
    7330 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
    7331 }
    7332 else
    7333 {
    7334 /* do not add pscostscore, if not available, also do not add into weightsum */
    7335 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
    7336 }
    7337 }
    7338
    7339 if( maxscore.vartype > 0.0 )
    7340 {
    7341 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
    7342 weightsum += conshdlrdata->branchvartypeweight;
    7343
    7344 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
    7345 }
    7346
    7347 assert(weightsum > 0.0); /* we should have got at least one valid score */
    7348 cands[c].weighted /= weightsum;
    7349
    7350 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
    7351 }
    7352}
    7353
    7354/** compare two branching candidates by their weighted score
    7355 *
    7356 * if weighted score is equal, use variable index of (aux)var
    7357 * if variables are the same, then use whether variable was added due to nonlinearity or fractionality
    7358 */
    7359static
    7360SCIP_DECL_SORTINDCOMP(branchcandCompare)
    7361{
    7362 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
    7363
    7364 if( cands[ind1].weighted != cands[ind2].weighted )
    7365 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
    7366
    7367 if( cands[ind1].var != cands[ind2].var )
    7368 return SCIPvarGetIndex(cands[ind1].var) - SCIPvarGetIndex(cands[ind2].var);
    7369
    7370 return cands[ind1].expr != NULL ? 1 : -1;
    7371}
    7372
    7373/** picks a candidate from array of branching candidates */
    7374static
    7376 SCIP* scip, /**< SCIP data structure */
    7377 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7378 BRANCHCAND* cands, /**< branching candidates */
    7379 int ncands, /**< number of candidates */
    7380 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
    7381 SCIP_SOL* sol, /**< relaxation solution, NULL for LP */
    7382 BRANCHCAND** selected /**< buffer to store selected branching candidates */
    7383 )
    7384{
    7385 SCIP_CONSHDLRDATA* conshdlrdata;
    7386 int* perm;
    7387 int c;
    7388 int left;
    7389 int right;
    7390 SCIP_Real threshold;
    7391
    7392 assert(cands != NULL);
    7393 assert(ncands >= 1);
    7394 assert(selected != NULL);
    7395
    7396 if( ncands == 1 )
    7397 {
    7398 *selected = cands;
    7399 return SCIP_OKAY;
    7400 }
    7401
    7402 /* if there are more than one candidate, then compute scores and select */
    7403
    7404 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7405 assert(conshdlrdata != NULL);
    7406
    7407 /* compute additional scores on branching candidates and weighted score */
    7408 scoreBranchingCandidates(scip, conshdlr, cands, ncands, considerfracnl, sol);
    7409
    7410 /* sort candidates by weighted score */
    7411 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
    7412 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
    7413
    7414 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
    7415 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
    7416 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
    7417
    7418 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
    7419 left = 0;
    7420 right = ncands - 1;
    7421 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
    7422 while( left < right )
    7423 {
    7424 int mid = (left + right) / 2;
    7425 if( cands[perm[mid]].weighted >= threshold )
    7426 left = mid + 1;
    7427 else
    7428 right = mid;
    7429 }
    7430 assert(left <= ncands);
    7431
    7432 if( left < ncands )
    7433 {
    7434 if( cands[perm[left]].weighted >= threshold )
    7435 {
    7436 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
    7437 ncands = left + 1;
    7438 }
    7439 else
    7440 {
    7441 assert(cands[perm[left]].weighted < threshold);
    7442 ncands = left;
    7443 }
    7444 }
    7445 assert(ncands > 0);
    7446
    7447 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
    7448 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
    7449 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
    7450
    7451 if( ncands > 1 )
    7452 {
    7453 /* choose at random from candidates 0..ncands-1 */
    7454 if( conshdlrdata->branchrandnumgen == NULL )
    7455 {
    7456 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
    7457 }
    7458 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
    7459 *selected = &cands[perm[c]];
    7460 }
    7461 else
    7462 *selected = &cands[perm[0]];
    7463
    7464 SCIPfreeBufferArray(scip, &perm);
    7465
    7466 return SCIP_OKAY;
    7467}
    7468
    7469/** do spatial branching or register branching candidates */
    7470static
    7472 SCIP* scip, /**< SCIP data structure */
    7473 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7474 SCIP_CONS** conss, /**< constraints to process */
    7475 int nconss, /**< number of constraints */
    7476 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
    7477 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    7478 SCIP_Longint soltag, /**< tag of solution */
    7479 SCIP_RESULT* result /**< pointer to store the result of branching */
    7480 )
    7481{
    7482 SCIP_CONSHDLRDATA* conshdlrdata;
    7483 BRANCHCAND* cands;
    7484 int ncands;
    7485 BRANCHCAND* selected = NULL;
    7486 SCIP_NODE* downchild;
    7487 SCIP_NODE* eqchild;
    7488 SCIP_NODE* upchild;
    7489
    7490 assert(conshdlr != NULL);
    7491 assert(result != NULL);
    7492
    7493 *result = SCIP_DIDNOTFIND;
    7494
    7495 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7496 assert(conshdlrdata != NULL);
    7497
    7498 if( conshdlrdata->branchexternal )
    7499 {
    7500 /* just register branching candidates as external */
    7501 SCIP_Bool success;
    7502
    7503 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
    7504 if( success )
    7505 *result = SCIP_INFEASIBLE;
    7506
    7507 return SCIP_OKAY;
    7508 }
    7509
    7510 /* collect branching candidates and their auxviol-score */
    7512 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
    7513
    7514 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
    7515 * we will return here and let the fallbacks in consEnfo() decide how to proceed
    7516 */
    7517 if( ncands == 0 )
    7518 goto TERMINATE;
    7519
    7520 /* here we include fractionality of integer variables into the branching score
    7521 * but if we know there will be no fractional integer variables, then we can shortcut and turn this off
    7522 */
    7523 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, sol == NULL && SCIPgetNLPBranchCands(scip) > 0, sol, &selected) );
    7524 assert(selected != NULL);
    7525 assert(selected->expr != NULL);
    7526
    7527 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(selected->var),
    7528 SCIPvarGetLbLocal(selected->var), SCIPvarGetUbLocal(selected->var)); )
    7529
    7530 SCIP_CALL( SCIPbranchVarVal(scip, selected->var, SCIPgetBranchingPoint(scip, selected->var, SCIP_INVALID), &downchild, &eqchild,
    7531 &upchild) );
    7532 if( downchild != NULL || eqchild != NULL || upchild != NULL )
    7533 *result = SCIP_BRANCHED;
    7534 else
    7535 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
    7536 *result = SCIP_REDUCEDDOM;
    7537
    7538 TERMINATE:
    7539 SCIPfreeBufferArray(scip, &cands);
    7540
    7541 return SCIP_OKAY;
    7542}
    7543
    7544/** call enforcement or estimate callback of nonlinear handler
    7545 *
    7546 * Calls the enforcement callback, if available.
    7547 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
    7548 *
    7549 * If cut is weak, but estimator is not tight, tries to add branching candidates.
    7550 */
    7551static
    7553 SCIP* scip, /**< SCIP main data structure */
    7554 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7555 SCIP_CONS* cons, /**< nonlinear constraint */
    7556 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
    7557 SCIP_EXPR* expr, /**< expression */
    7558 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
    7559 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
    7560 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
    7561 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
    7562 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
    7563 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
    7564 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
    7565 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
    7566 SCIP_RESULT* result /**< pointer to store the result */
    7567 )
    7568{
    7569 assert(result != NULL);
    7570
    7571 /* call enforcement callback of the nlhdlr */
    7572 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
    7573 allowweakcuts, separated, inenforcement, branchcandonly, result) );
    7574
    7575 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
    7576 if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
    7577 {
    7578 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
    7579 SCIPnlhdlrGetName(nlhdlr), *result); )
    7580 return SCIP_OKAY;
    7581 }
    7582 else
    7583 {
    7584 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
    7585 }
    7586
    7587 *result = SCIP_DIDNOTFIND;
    7588
    7589 /* now call the estimator callback of the nlhdlr */
    7590 if( SCIPnlhdlrHasEstimate(nlhdlr) )
    7591 {
    7592 SCIP_VAR* auxvar;
    7593 SCIP_Bool sepasuccess = FALSE;
    7594 SCIP_Bool branchscoresuccess = FALSE;
    7595 SCIP_PTRARRAY* rowpreps;
    7596 int minidx;
    7597 int maxidx;
    7598 int r;
    7599 SCIP_ROWPREP* rowprep;
    7600
    7601 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
    7602
    7603 auxvar = SCIPgetExprAuxVarNonlinear(expr);
    7604 assert(auxvar != NULL);
    7605
    7606 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
    7607 SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
    7608
    7609 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
    7610 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
    7611
    7612 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
    7613
    7614 if( !sepasuccess )
    7615 {
    7616 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
    7617 SCIPnlhdlrGetName(nlhdlr)); )
    7618 }
    7619
    7620 for( r = minidx; r <= maxidx; ++r )
    7621 {
    7622 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
    7623
    7624 assert(rowprep != NULL);
    7625 assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
    7626
    7627 if( !branchcandonly )
    7628 {
    7629 /* complete estimator to cut */
    7630 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
    7631
    7632 /* add the cut and/or branching scores
    7633 * (branching scores that could be added here are to deal with bad numerics of cuts; we skip these if branchcandonly)
    7634 */
    7635 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
    7636 auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
    7637 }
    7638
    7639 SCIPfreeRowprep(scip, &rowprep);
    7640 }
    7641
    7642 if( branchcandonly && branchscoresuccess )
    7643 {
    7644 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s added branching candidates\n", SCIPnlhdlrGetName(nlhdlr)); )
    7645 *result = SCIP_BRANCHED;
    7646 }
    7647
    7648 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
    7649 }
    7650
    7651 return SCIP_OKAY;
    7652}
    7653
    7654/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
    7655 *
    7656 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
    7657 */
    7658static
    7660 SCIP* scip, /**< SCIP data structure */
    7661 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    7662 SCIP_CONS* cons, /**< nonlinear constraint */
    7663 SCIP_EXPR* expr, /**< expression */
    7664 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
    7665 SCIP_Longint soltag, /**< tag of solution */
    7666 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
    7667 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
    7668 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
    7669 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    7670 )
    7671{
    7672 SCIP_CONSHDLRDATA* conshdlrdata;
    7673 SCIP_EXPR_OWNERDATA* ownerdata;
    7674 SCIP_Real origviol;
    7675 SCIP_Bool underestimate;
    7676 SCIP_Bool overestimate;
    7677 SCIP_Real auxviol;
    7678 SCIP_Bool auxunderestimate;
    7679 SCIP_Bool auxoverestimate;
    7680 SCIP_RESULT hdlrresult;
    7681 int e;
    7682
    7683 assert(scip != NULL);
    7684 assert(expr != NULL);
    7685 assert(result != NULL);
    7686
    7687 ownerdata = SCIPexprGetOwnerData(expr);
    7688 assert(ownerdata != NULL);
    7689 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
    7690
    7691 *result = SCIP_DIDNOTFIND;
    7692
    7693 /* make sure that this expression has been evaluated */
    7694 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
    7695
    7696 /* decide whether under- or overestimate is required and get amount of violation */
    7697 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
    7698
    7699 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7700 assert(conshdlrdata != NULL);
    7701
    7702 /* no sufficient violation w.r.t. the original variables -> skip expression */
    7703 if( !overestimate && !underestimate )
    7704 {
    7705 return SCIP_OKAY;
    7706 }
    7707
    7708 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
    7709 for( e = 0; e < ownerdata->nenfos; ++e )
    7710 {
    7711 SCIP_NLHDLR* nlhdlr;
    7712
    7713 /* skip nlhdlr that do not want to participate in any separation */
    7714 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
    7715 continue;
    7716
    7717 /* if looking for branching candidates only, then skip nlhdlr that wouldn't created branching candidates */
    7718 if( branchcandonly && !ownerdata->enfos[e]->sepaaboveusesactivity && !ownerdata->enfos[e]->sepabelowusesactivity )
    7719 continue;
    7720
    7721 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    7722 assert(nlhdlr != NULL);
    7723
    7724 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
    7725 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
    7726 ENFOLOG(
    7727 SCIPinfoMessage(scip, enfologfile, " expr ");
    7728 SCIPprintExpr(scip, expr, enfologfile);
    7729 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
    7730 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
    7731 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
    7732 )
    7733
    7734 /* TODO if expr is root of constraint (consdata->expr == expr),
    7735 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
    7736 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
    7737 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
    7738 * so we should enforce in these auxiliaries first
    7739 * if changing this here, we must also adapt analyzeViolation()
    7740 */
    7741
    7742 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
    7743 assert(auxviol >= 0.0);
    7744
    7745 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
    7746 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
    7747 {
    7748 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
    7749 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
    7750 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
    7751
    7752 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
    7753 continue;
    7754 }
    7755
    7756 /* if aux-violation is small (below feastol) and we look only for strong cuts, then it's unlikely to give a strong cut, so skip it */
    7757 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
    7758 {
    7759 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
    7760 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
    7761 underestimate, overestimate); )
    7762
    7763 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
    7764 continue;
    7765 }
    7766
    7767 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
    7768 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
    7769 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
    7770
    7771 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
    7772 * wants to be called for separation on this side, then call separation of nlhdlr
    7773 */
    7774 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepaaboveusesactivity) )
    7775 {
    7776 /* call the separation or estimation callback of the nonlinear handler for overestimation */
    7777 hdlrresult = SCIP_DIDNOTFIND;
    7778 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
    7779 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
    7780
    7781 if( hdlrresult == SCIP_CUTOFF )
    7782 {
    7783 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
    7784 *result = SCIP_CUTOFF;
    7785 ownerdata->lastenforced = conshdlrdata->enforound;
    7786 break;
    7787 }
    7788
    7789 if( hdlrresult == SCIP_SEPARATED )
    7790 {
    7791 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
    7792 *result = SCIP_SEPARATED;
    7793 ownerdata->lastenforced = conshdlrdata->enforound;
    7794 /* TODO or should we give other nlhdlr another chance? (also #3070) */
    7795 break;
    7796 }
    7797
    7798 if( hdlrresult == SCIP_REDUCEDDOM )
    7799 {
    7800 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
    7801 *result = SCIP_REDUCEDDOM;
    7802 ownerdata->lastenforced = conshdlrdata->enforound;
    7803 /* TODO or should we always just stop here? */
    7804 }
    7805
    7806 if( hdlrresult == SCIP_BRANCHED )
    7807 {
    7808 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
    7809 assert(inenforcement);
    7810
    7811 /* separation and domain reduction takes precedence over branching */
    7812 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
    7813 if( *result == SCIP_DIDNOTFIND )
    7814 *result = SCIP_BRANCHED;
    7815 ownerdata->lastenforced = conshdlrdata->enforound;
    7816 }
    7817 }
    7818
    7819 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
    7820 * wants to be called for separation on this side, then call separation of nlhdlr
    7821 */
    7822 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepabelowusesactivity) )
    7823 {
    7824 /* call the separation or estimation callback of the nonlinear handler for underestimation */
    7825 hdlrresult = SCIP_DIDNOTFIND;
    7826 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
    7827 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
    7828
    7829 if( hdlrresult == SCIP_CUTOFF )
    7830 {
    7831 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
    7832 *result = SCIP_CUTOFF;
    7833 ownerdata->lastenforced = conshdlrdata->enforound;
    7834 break;
    7835 }
    7836
    7837 if( hdlrresult == SCIP_SEPARATED )
    7838 {
    7839 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
    7840 *result = SCIP_SEPARATED;
    7841 ownerdata->lastenforced = conshdlrdata->enforound;
    7842 /* TODO or should we give other nlhdlr another chance? (also #3070) */
    7843 break;
    7844 }
    7845
    7846 if( hdlrresult == SCIP_REDUCEDDOM )
    7847 {
    7848 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
    7849 *result = SCIP_REDUCEDDOM;
    7850 ownerdata->lastenforced = conshdlrdata->enforound;
    7851 /* TODO or should we always just stop here? */
    7852 }
    7853
    7854 if( hdlrresult == SCIP_BRANCHED )
    7855 {
    7856 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
    7857 assert(inenforcement);
    7858
    7859 /* separation takes precedence over branching */
    7860 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
    7861 if( *result == SCIP_DIDNOTFIND )
    7862 *result = SCIP_BRANCHED;
    7863 ownerdata->lastenforced = conshdlrdata->enforound;
    7864 }
    7865 }
    7866 }
    7867
    7868 return SCIP_OKAY;
    7869}
    7870
    7871/** helper function to enforce a single constraint */
    7872static
    7874 SCIP* scip, /**< SCIP data structure */
    7875 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7876 SCIP_CONS* cons, /**< constraint to process */
    7877 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    7878 SCIP_Longint soltag, /**< tag of solution */
    7879 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
    7880 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
    7881 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
    7882 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
    7883 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
    7884 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
    7885 )
    7886{
    7887 SCIP_CONSDATA* consdata;
    7888 SCIP_CONSHDLRDATA* conshdlrdata;
    7889 SCIP_EXPR* expr;
    7890
    7891 assert(conshdlr != NULL);
    7892 assert(cons != NULL);
    7893 assert(it != NULL);
    7894 assert(result != NULL);
    7895 assert(success != NULL);
    7896
    7897 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7898 assert(conshdlrdata != NULL);
    7899
    7900 consdata = SCIPconsGetData(cons);
    7901 assert(consdata != NULL);
    7902 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
    7903
    7904 *success = FALSE;
    7905
    7906 if( inenforcement && !branchcandonly && !consdata->ispropagated )
    7907 {
    7908 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
    7909 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
    7910 * (TODO: nlhdlr tells us now whether they do and so we could skip).
    7911 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
    7912 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
    7913 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
    7914 * confuse the stalling check for how long to do separation).
    7915 */
    7916 SCIP_Bool infeasible;
    7917 int ntightenings;
    7918
    7919 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
    7920 if( infeasible )
    7921 {
    7922 *result = SCIP_CUTOFF;
    7923 return SCIP_OKAY;
    7924 }
    7925 /* if we tightened an auxvar bound, we better communicate that */
    7926 if( ntightenings > 0 )
    7927 *result = SCIP_REDUCEDDOM;
    7928 }
    7929
    7930 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    7931 {
    7932 SCIP_EXPR_OWNERDATA* ownerdata;
    7933 SCIP_RESULT resultexpr;
    7934
    7935 ownerdata = SCIPexprGetOwnerData(expr);
    7936 assert(ownerdata != NULL);
    7937
    7938 /* we can only enforce if there is an auxvar to compare with */
    7939 if( ownerdata->auxvar == NULL )
    7940 continue;
    7941
    7942 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
    7943 if( ownerdata->lastenforced == conshdlrdata->enforound )
    7944 {
    7945 ENFOLOG(
    7946 SCIPinfoMessage(scip, enfologfile, " skip expr ");
    7947 SCIPprintExpr(scip, expr, enfologfile);
    7948 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
    7949 )
    7950 *success = TRUE;
    7951 continue;
    7952 }
    7953
    7954 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, branchcandonly, &resultexpr) );
    7955
    7956 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
    7957 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
    7958 if( ownerdata->lastenforced == conshdlrdata->enforound ) /* cppcheck-suppress knownConditionTrueFalse */
    7959 *success = TRUE;
    7960
    7961 if( resultexpr == SCIP_CUTOFF )
    7962 {
    7963 *result = SCIP_CUTOFF;
    7964 break;
    7965 }
    7966
    7967 if( resultexpr == SCIP_SEPARATED )
    7968 *result = SCIP_SEPARATED;
    7969
    7970 if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
    7971 *result = SCIP_REDUCEDDOM;
    7972
    7973 if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
    7974 *result = SCIP_BRANCHED;
    7975 }
    7976
    7977 return SCIP_OKAY;
    7978}
    7979
    7980/** try to separate violated constraints and, if in enforcement, register branching scores
    7981 *
    7982 * If branchcandonly=TRUE, then do not separate or propagate, but register branching scores only.
    7983 *
    7984 * Sets result to
    7985 * - SCIP_DIDNOTFIND, if nothing of the below has been done
    7986 * - SCIP_CUTOFF, if node can be cutoff,
    7987 * - SCIP_SEPARATED, if a cut has been added,
    7988 * - SCIP_REDUCEDDOM, if a domain reduction has been found or a variable got fixed (in an attempt to branch on it),
    7989 * - SCIP_BRANCHED, if branching has been done (if branchcandonly=TRUE, then collected branching candidates only),
    7990 * - SCIP_INFEASIBLE, if external branching candidates were registered
    7991 */
    7992static
    7994 SCIP* scip, /**< SCIP data structure */
    7995 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7996 SCIP_CONS** conss, /**< constraints to process */
    7997 int nconss, /**< number of constraints */
    7998 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    7999 SCIP_Longint soltag, /**< tag of solution */
    8000 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
    8001 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
    8002 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
    8003 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    8004 )
    8005{
    8006 SCIP_CONSHDLRDATA* conshdlrdata;
    8007 SCIP_EXPRITER* it;
    8008 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
    8009 int c;
    8010
    8011 assert(conshdlr != NULL);
    8012 assert(conss != NULL || nconss == 0);
    8013 assert(result != NULL);
    8014
    8015 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8016 assert(conshdlrdata != NULL);
    8017
    8018 /* increase tag to tell whether branching scores in expression belong to this sweep
    8019 * and which expressions have already been enforced in this sweep
    8020 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
    8021 */
    8022 ++(conshdlrdata->enforound);
    8023
    8024 *result = SCIP_DIDNOTFIND;
    8025
    8028
    8029 for( c = 0; c < nconss; ++c )
    8030 {
    8031 assert(conss != NULL && conss[c] != NULL);
    8032
    8033 /* skip constraints that are not enabled or deleted */
    8034 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
    8035 continue;
    8036 assert(SCIPconsIsActive(conss[c]));
    8037
    8038 /* skip constraints that have separation disabled if we are only in separation */
    8039 if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
    8040 continue;
    8041
    8042 /* skip non-violated constraints */
    8043 if( !isConsViolated(scip, conss[c]) )
    8044 continue;
    8045
    8046 ENFOLOG(
    8047 {
    8048 SCIP_CONSDATA* consdata;
    8049 int i;
    8050 consdata = SCIPconsGetData(conss[c]);
    8051 assert(consdata != NULL);
    8052 SCIPinfoMessage(scip, enfologfile, " constraint ");
    8053 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
    8054 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
    8055 for( i = 0; i < consdata->nvarexprs; ++i )
    8056 {
    8057 SCIP_VAR* var;
    8058 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    8059 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
    8060 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
    8061 }
    8062 })
    8063
    8064 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, branchcandonly, result, &consenforced) );
    8065
    8066 if( *result == SCIP_CUTOFF )
    8067 break;
    8068
    8069 if( !consenforced && inenforcement && !branchcandonly )
    8070 {
    8071 SCIP_Real viol;
    8072
    8073 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
    8074 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
    8075 {
    8076 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
    8077 "cuts allowed\n", SCIPconsGetName(conss[c])); )
    8078
    8079 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, branchcandonly, result, &consenforced) );
    8080
    8081 if( consenforced )
    8082 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
    8083
    8084 if( *result == SCIP_CUTOFF )
    8085 break;
    8086 }
    8087 }
    8088 }
    8089
    8090 SCIPfreeExpriter(&it);
    8091
    8092 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
    8093
    8094 if( *result == SCIP_BRANCHED && !branchcandonly )
    8095 {
    8096 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
    8097 * branching
    8098 */
    8099 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
    8100
    8101 /* branching should either have branched: result == SCIP_BRANCHED,
    8102 * or fixed a variable: result == SCIP_REDUCEDDOM,
    8103 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
    8104 * or have not done anything: result == SCIP_DIDNOTFIND
    8105 */
    8106 assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
    8107 }
    8108
    8109 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
    8110
    8111 return SCIP_OKAY;
    8112}
    8113
    8114/** decide whether to branch on fractional integer or nonlinear variable
    8115 *
    8116 * The routine collects spatial branching candidates by a call to enforceConstraints(branchcandonly=TRUE)
    8117 * and collectBranchingCandidates(). Then it adds fractional integer variables to the candidate list.
    8118 * Variables that are candidate for both spatial branching and fractionality are considered as two separate candidates.
    8119 * selectBranchingCandidate() then selects a variable for branching from the joined candidate list.
    8120 * If the selected variable is a fractional integer one, then branchintegral=TRUE is returned, otherwise FALSE.
    8121 * Some shortcuts exist for cases where there are no candidates of the one kind or the other.
    8122 */
    8123static
    8125 SCIP* scip, /**< SCIP data structure */
    8126 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8127 SCIP_CONS** conss, /**< constraints to process */
    8128 int nconss, /**< number of constraints */
    8129 SCIP_Longint soltag, /**< tag of LP solution */
    8130 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
    8131 SCIP_Bool* branchintegral, /**< buffer to store whether to branch on fractional integer variables first */
    8132 SCIP_Bool* cutoff /**< buffer to store whether infeasibility has been detected */
    8133 )
    8134{
    8135 SCIP_RESULT result;
    8136 int nlpcands;
    8137 SCIP_VAR** lpcands; /* fractional integer variables */
    8138 SCIP_Real* lpcandsfrac; /* fractionalities */
    8139 BRANCHCAND* cands;
    8140 BRANCHCAND* selected;
    8141 int ncands;
    8142 int c;
    8143
    8144 assert(scip != NULL);
    8145 assert(conshdlr != NULL);
    8146 assert(conss != NULL);
    8147 assert(nconss > 0);
    8148 assert(branchintegral != NULL);
    8149 assert(cutoff != NULL);
    8150
    8151 *branchintegral = FALSE;
    8152 *cutoff = FALSE;
    8153
    8155 return SCIP_OKAY;
    8156
    8157 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, NULL, (SCIP_Longint)0, TRUE, TRUE, maxrelconsviol, &result) );
    8158 switch( result )
    8159 {
    8160 case SCIP_DIDNOTFIND:
    8161 /* no branching candidates found could mean that the LP solution is in a convex region */
    8162 *branchintegral = TRUE;
    8163 return SCIP_OKAY;
    8164
    8165 case SCIP_CUTOFF:
    8166 /* probably cannot happen, but easy to handle */
    8167 *cutoff = TRUE;
    8168 return SCIP_OKAY;
    8169
    8170 case SCIP_SEPARATED:
    8171 case SCIP_REDUCEDDOM:
    8172 /* we asked enforceConstraints() to collect branching candidates only, it shouldn't have separated or propagated */
    8173 SCIPerrorMessage("Unexpected separation or propagation from enforceConstraints(branchcandonly = TRUE)\n");
    8174 return SCIP_ERROR;
    8175
    8176 case SCIP_BRANCHED:
    8177 /* actually meaning that branching candidates were registered (the result for which we have gone through all this effort) */
    8178 break;
    8179
    8180 case SCIP_INFEASIBLE:
    8181 /* should not happen (enforceConstraints() returns this if external branching candidates were registered in branching(),
    8182 * but this was disabled by branchcandonly = TRUE)
    8183 */
    8184 default:
    8185 SCIPerrorMessage("Unexpected return from enforceConstraints(branchcandonly = TRUE)\n");
    8186 return SCIP_ERROR;
    8187 } /*lint !e788*/
    8188
    8189 /* collect spatial branching candidates and their auxviol-score */
    8191 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, NULL, soltag, cands, &ncands) );
    8192
    8193 /* add fractional integer variables to branching candidates */
    8194 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) );
    8195
    8196 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding %d fractional integer variables to branching candidates\n", nlpcands); )
    8197
    8198 for( c = 0; c < nlpcands; ++c )
    8199 {
    8200 assert(SCIPvarGetType(lpcands[c]) != SCIP_VARTYPE_CONTINUOUS);
    8201 assert(ncands < SCIPgetNVars(scip) + SCIPgetNLPBranchCands(scip));
    8202 cands[ncands].expr = NULL;
    8203 cands[ncands].var = lpcands[c];
    8204 cands[ncands].auxviol = 0.0;
    8205 cands[ncands].fractionality = lpcandsfrac[c];
    8206 ++ncands;
    8207 }
    8208
    8209 /* select a variable for branching
    8210 * to keep things separate, do not include fractionality of integer variables into scores of spatial branching candidates
    8211 * the same variables appear among the candidates for branching on integrality, where its fractionality is considered
    8212 */
    8213 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, FALSE, NULL, &selected) );
    8214 assert(selected != NULL);
    8215
    8216 if( selected->expr == NULL )
    8217 {
    8218 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " fractional variable <%s> selected for branching; fall back to cons_integral\n", SCIPvarGetName(selected->var)); )
    8219
    8220 *branchintegral = TRUE;
    8221 }
    8222
    8223 SCIPfreeBufferArray(scip, &cands);
    8224
    8225 return SCIP_OKAY;
    8226}
    8227
    8228/** decide whether to consider spatial branching before integrality has been enforced
    8229 *
    8230 * This decides whether we are still at a phase where we always want to branch on fractional integer variables if any (return TRUE),
    8231 * or whether branchingIntegralOrNonlinear() should be used (return FALSE).
    8232 *
    8233 * This essentially checks whether the average pseudo cost count exceeds the value of parameter branchmixfractional.
    8234 */
    8235static
    8237 SCIP* scip, /**< SCIP data structure */
    8238 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8239 SCIP_SOL* sol /**< solution to be enforced */
    8240 )
    8241{
    8242 SCIP_CONSHDLRDATA* conshdlrdata;
    8243
    8244 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8245 assert(conshdlrdata != NULL);
    8246
    8247 /* if LP still unbounded, then work on nonlinear constraints first */
    8249 return FALSE;
    8250
    8251 /* no branching in cons_integral if no integer variables */
    8253 return FALSE;
    8254
    8255 /* no branching in cons_integral if LP solution not fractional */
    8256 if( sol == NULL && SCIPgetNLPBranchCands(scip) == 0 )
    8257 return FALSE;
    8258
    8259 /* no branching in cons_integral if relax solution not fractional */
    8260 if( sol != NULL )
    8261 {
    8262 SCIP_Bool isfractional = FALSE;
    8263 SCIP_VAR** vars;
    8264 int nbinvars;
    8265 int nintvars;
    8266 int i;
    8267
    8268 vars = SCIPgetVars(scip);
    8269 nbinvars = SCIPgetNBinVars(scip);
    8270 nintvars = SCIPgetNIntVars(scip);
    8271
    8272 for( i = 0; i < nbinvars + nintvars && !isfractional; ++i )
    8273 {
    8274 assert(vars[i] != NULL);
    8275 assert(SCIPvarIsIntegral(vars[i]));
    8276
    8277 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[i])) )
    8278 isfractional = TRUE;
    8279 }
    8280
    8281 if( !isfractional )
    8282 return FALSE;
    8283 }
    8284
    8285 /* branchmixfractional being infinity means that integral should always go first */
    8286 if( SCIPisInfinity(scip, conshdlrdata->branchmixfractional) )
    8287 return TRUE;
    8288
    8289 /* branchmixfractional being 0.0 means we do not wait for any pseudocosts to be available */
    8290 if( conshdlrdata->branchmixfractional == 0.0 )
    8291 return FALSE;
    8292
    8293 /* if not yet enough pseudocosts for down or up direction, then branch on fractionality
    8294 * @todo this gives the total pseudocost count divided by the number of discrete variables
    8295 * if we updated pseudocost after branching on continuous variables, wouldn't this be incorrect? (#3637)
    8296 */
    8297 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_DOWNWARDS) < conshdlrdata->branchmixfractional )
    8298 return TRUE;
    8299 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_UPWARDS) < conshdlrdata->branchmixfractional )
    8300 return TRUE;
    8301
    8302 /* we may have decent pseudocosts, so go for rule that chooses between fractional and spatial branching based on candidates */
    8303 return FALSE;
    8304}
    8305
    8306/** collect (and print (if debugging enfo)) information on violation in expressions
    8307 *
    8308 * assumes that constraint violations have been computed
    8309 */
    8310static
    8312 SCIP* scip, /**< SCIP data structure */
    8313 SCIP_CONS** conss, /**< constraints */
    8314 int nconss, /**< number of constraints */
    8315 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
    8316 SCIP_Longint soltag, /**< tag of solution */
    8317 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
    8318 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
    8319 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
    8320 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
    8321 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
    8322 )
    8323{
    8324 SCIP_CONSDATA* consdata;
    8325 SCIP_EXPRITER* it;
    8326 SCIP_EXPR* expr;
    8327 SCIP_Real v;
    8328 int c;
    8329
    8330 assert(conss != NULL || nconss == 0);
    8331 assert(maxabsconsviol != NULL);
    8332 assert(maxrelconsviol != NULL);
    8333 assert(maxauxviol != NULL);
    8334 assert(maxvarboundviol != NULL);
    8335
    8338
    8339 *maxabsconsviol = 0.0;
    8340 *maxrelconsviol = 0.0;
    8341 *minauxviol = SCIPinfinity(scip);
    8342 *maxauxviol = 0.0;
    8343 *maxvarboundviol = 0.0;
    8344
    8345 for( c = 0; c < nconss; ++c )
    8346 {
    8347 assert(conss != NULL && conss[c] != NULL);
    8348
    8349 consdata = SCIPconsGetData(conss[c]);
    8350 assert(consdata != NULL);
    8351
    8352 /* skip constraints that are not enabled, deleted, or have separation disabled */
    8353 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
    8354 continue;
    8355 assert(SCIPconsIsActive(conss[c]));
    8356
    8357 v = getConsAbsViolation(conss[c]);
    8358 *maxabsconsviol = MAX(*maxabsconsviol, v);
    8359
    8360 /* skip non-violated constraints */
    8361 if( !isConsViolated(scip, conss[c]) )
    8362 continue;
    8363
    8364 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
    8365 *maxrelconsviol = MAX(*maxrelconsviol, v);
    8366
    8367 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    8368 {
    8369 SCIP_EXPR_OWNERDATA* ownerdata;
    8370 SCIP_Real auxvarvalue;
    8371 SCIP_Real auxvarlb;
    8372 SCIP_Real auxvarub;
    8373 SCIP_Bool violunder;
    8374 SCIP_Bool violover;
    8375 SCIP_Real origviol;
    8376 SCIP_Real auxviol;
    8377 int e;
    8378
    8379 ownerdata = SCIPexprGetOwnerData(expr);
    8380 assert(ownerdata != NULL);
    8381
    8382 if( ownerdata->auxvar == NULL )
    8383 {
    8384 /* check violation of variable bounds of original variable */
    8385 if( SCIPisExprVar(scip, expr) )
    8386 {
    8387 SCIP_VAR* var;
    8388 var = SCIPgetVarExprVar(expr);
    8389 auxvarvalue = SCIPgetSolVal(scip, sol, var);
    8390 auxvarlb = SCIPvarGetLbLocal(var);
    8391 auxvarub = SCIPvarGetUbLocal(var);
    8392
    8393 origviol = 0.0;
    8394 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
    8395 origviol = auxvarlb - auxvarvalue;
    8396 else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
    8397 origviol = auxvarvalue - auxvarub;
    8398 if( origviol <= 0.0 )
    8399 continue;
    8400
    8401 *maxvarboundviol = MAX(*maxvarboundviol, origviol);
    8402
    8403 ENFOLOG(
    8404 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
    8405 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
    8406 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
    8407 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
    8408 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
    8409 SCIPinfoMessage(scip, enfologfile, "\n");
    8410 )
    8411 }
    8412
    8413 continue;
    8414 }
    8415
    8416 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
    8417 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
    8418 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
    8419
    8420 /* check violation of variable bounds of auxiliary variable */
    8421 if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
    8422 *maxvarboundviol = auxvarlb - auxvarvalue;
    8423 else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
    8424 *maxvarboundviol = auxvarvalue - auxvarub;
    8425
    8426 origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
    8427
    8428 ENFOLOG(
    8429 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
    8430 {
    8431 SCIPinfoMessage(scip, enfologfile, "expr ");
    8432 SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
    8433 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
    8434
    8435 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
    8436 if( origviol > 0.0 )
    8437 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
    8438 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
    8439 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
    8440 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
    8441 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
    8442 SCIPinfoMessage(scip, enfologfile, "\n");
    8443 }
    8444 )
    8445
    8446 /* no violation w.r.t. the original variables -> skip expression */
    8447 if( origviol == 0.0 )
    8448 continue;
    8449
    8450 /* compute aux-violation for each nonlinear handlers */
    8451 for( e = 0; e < ownerdata->nenfos; ++e )
    8452 {
    8453 SCIP_NLHDLR* nlhdlr;
    8454
    8455 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
    8456 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
    8457 continue;
    8458
    8459 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    8460 assert(nlhdlr != NULL);
    8461
    8462 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
    8463 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
    8464
    8465 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
    8466
    8467 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
    8468
    8469 if( auxviol > 0.0 )
    8470 {
    8471 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
    8472 *maxauxviol = MAX(*maxauxviol, auxviol);
    8473 *minauxviol = MIN(*minauxviol, auxviol);
    8474 }
    8475 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
    8476 }
    8477 }
    8478 }
    8479
    8480 SCIPfreeExpriter(&it);
    8481
    8482 return SCIP_OKAY;
    8483} /*lint !e715*/
    8484
    8485/** enforcement of constraints called by enfolp and enforelax */
    8486static
    8488 SCIP* scip, /**< SCIP data structure */
    8489 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8490 SCIP_CONS** conss, /**< constraints to process */
    8491 int nconss, /**< number of constraints */
    8492 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    8493 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    8494 )
    8495{
    8496 SCIP_CONSHDLRDATA* conshdlrdata;
    8497 SCIP_Real maxabsconsviol;
    8498 SCIP_Real maxrelconsviol;
    8499 SCIP_Real minauxviol;
    8500 SCIP_Real maxauxviol;
    8501 SCIP_Real maxvarboundviol;
    8502 SCIP_Longint soltag;
    8503 SCIP_Bool branchintegral;
    8504 int nnotify;
    8505 int c;
    8506
    8507 if( branchingIntegralFirst(scip, conshdlr, sol) )
    8508 {
    8509 /* let cons_integral handle enforcement */
    8510 *result = SCIP_INFEASIBLE;
    8511 return SCIP_OKAY;
    8512 }
    8513
    8514 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8515 assert(conshdlr != NULL);
    8516
    8517 soltag = SCIPgetExprNewSoltag(scip);
    8518
    8519 *result = SCIP_FEASIBLE;
    8520 for( c = 0; c < nconss; ++c )
    8521 {
    8522 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
    8523
    8524 if( isConsViolated(scip, conss[c]) )
    8525 *result = SCIP_INFEASIBLE;
    8526 }
    8527
    8528 if( *result == SCIP_FEASIBLE )
    8529 {
    8530 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
    8532 return SCIP_OKAY;
    8533 }
    8534
    8535 SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
    8536 &minauxviol, &maxauxviol, &maxvarboundviol) );
    8537
    8538 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
    8539 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
    8540 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
    8541 maxvarboundviol, SCIPgetLPFeastol(scip)); )
    8542
    8543 assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
    8544
    8545 /* look at fractional and nonlinear branching candidates and decide whether to branch on fractional vars, first */
    8546 if( sol == NULL )
    8547 {
    8548 SCIP_Bool cutoff;
    8549
    8550 SCIP_CALL( branchingIntegralOrNonlinear(scip, conshdlr, conss, nconss, soltag, maxrelconsviol, &branchintegral, &cutoff) );
    8551 if( cutoff )
    8552 {
    8553 *result = SCIP_CUTOFF;
    8554 return SCIP_OKAY;
    8555 }
    8556 if( branchintegral )
    8557 {
    8558 /* let cons_integral handle enforcement */
    8559 *result = SCIP_INFEASIBLE;
    8560 return SCIP_OKAY;
    8561 }
    8562 }
    8563
    8564 /* try to propagate */
    8565 if( conshdlrdata->propinenforce )
    8566 {
    8567 SCIP_RESULT propresult;
    8568 int nchgbds = 0;
    8569
    8570 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
    8571
    8572 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
    8573 {
    8574 *result = propresult;
    8575 return SCIP_OKAY;
    8576 }
    8577 }
    8578
    8579 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
    8580 * all violated expr/auxvar in violated constraints)
    8581 */
    8582 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
    8583 sol == NULL )
    8584 {
    8585 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
    8586 ++conshdlrdata->ntightenlp;
    8587
    8588 *result = SCIP_SOLVELP;
    8589
    8590 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
    8591 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
    8592
    8593 return SCIP_OKAY;
    8594 }
    8595
    8596 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
    8597 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
    8598 */
    8599 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
    8600 {
    8601 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
    8602 ++conshdlrdata->ntightenlp;
    8603
    8604 *result = SCIP_SOLVELP;
    8605
    8606 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
    8607
    8608 return SCIP_OKAY;
    8609 }
    8610
    8611 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, FALSE, maxrelconsviol, result) );
    8612
    8613 if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
    8614 *result == SCIP_INFEASIBLE )
    8615 return SCIP_OKAY;
    8616
    8617 assert(*result == SCIP_DIDNOTFIND);
    8618
    8619 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
    8620 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
    8621
    8622 if( sol == NULL && SCIPgetNLPBranchCands(scip) > 0 )
    8623 {
    8624 /* if there are still fractional integer variables, then let cons_integral go first */
    8625 *result = SCIP_INFEASIBLE;
    8626 return SCIP_OKAY;
    8627 }
    8628
    8629 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
    8630 {
    8631 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
    8632 ++conshdlrdata->ntightenlp;
    8633
    8634 *result = SCIP_SOLVELP;
    8635
    8636 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
    8637 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
    8638
    8639 return SCIP_OKAY;
    8640 }
    8641
    8642 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
    8643 SCIPgetLPFeastol(scip)) && sol == NULL )
    8644 {
    8645 /* try whether tighten the LP feasibility tolerance could help
    8646 * maybe it is just some cut that hasn't been taken into account sufficiently
    8647 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
    8648 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
    8649 * until the LP feastol reaches epsilon
    8650 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
    8651 * when maxauxviol is above LP feastol)
    8652 */
    8653 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
    8654 ++conshdlrdata->ndesperatetightenlp;
    8655
    8656 *result = SCIP_SOLVELP;
    8657
    8658 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
    8659
    8660 return SCIP_OKAY;
    8661 }
    8662
    8663 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
    8664 if( !conshdlrdata->propinenforce )
    8665 {
    8666 SCIP_RESULT propresult;
    8667 int nchgbds = 0;
    8668
    8669 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
    8670
    8671 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
    8672 {
    8673 *result = propresult;
    8674 return SCIP_OKAY;
    8675 }
    8676 }
    8677
    8678 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
    8679 * now look if we find any unfixed variable that we could still branch on
    8680 */
    8681 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
    8682
    8683 if( nnotify > 0 )
    8684 {
    8685 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
    8686 ++conshdlrdata->ndesperatebranch;
    8687
    8688 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
    8689
    8690 return SCIP_OKAY;
    8691 }
    8692
    8693 /* if everything is fixed in violated constraints, then let's cut off the node
    8694 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
    8695 * result may not be conclusive (when constraint violations are small)
    8696 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
    8697 * sufficiently (see st_e40)
    8698 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
    8699 * not "desperate", but a pretty obvious thing to do
    8700 */
    8701 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
    8702 *result = SCIP_CUTOFF;
    8703
    8704 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
    8705 if( !SCIPisZero(scip, maxvarboundviol) )
    8706 ++conshdlrdata->ndesperatecutoff;
    8707
    8708 return SCIP_OKAY;
    8709}
    8710
    8711/** separation for all violated constraints to be used by SEPA callbacks */
    8712static
    8714 SCIP* scip, /**< SCIP data structure */
    8715 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8716 SCIP_CONS** conss, /**< constraints to process */
    8717 int nconss, /**< number of constraints */
    8718 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    8719 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    8720 )
    8721{
    8722 SCIP_Longint soltag;
    8723 SCIP_Bool haveviol = FALSE;
    8724 int c;
    8725
    8726 *result = SCIP_DIDNOTFIND;
    8727
    8728 soltag = SCIPgetExprNewSoltag(scip);
    8729
    8730 /* compute violations */
    8731 for( c = 0; c < nconss; ++c )
    8732 {
    8733 assert(conss[c] != NULL);
    8734
    8735 /* skip constraints that are not enabled, deleted, or have separation disabled */
    8736 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
    8737 continue;
    8738 assert(SCIPconsIsActive(conss[c]));
    8739
    8740 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
    8741
    8742 if( isConsViolated(scip, conss[c]) )
    8743 haveviol = TRUE;
    8744 }
    8745
    8746 /* if none of our constraints are violated, don't attempt separation */
    8747 if( !haveviol )
    8748 {
    8749 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
    8750 return SCIP_OKAY;
    8751 }
    8752
    8753 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
    8754
    8755 /* call separation */
    8756 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, FALSE, SCIP_INVALID, result) );
    8757
    8758 return SCIP_OKAY;
    8759}
    8760
    8761/** hash key retrieval function for bilinear term entries */
    8762static
    8763SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
    8764{ /*lint --e{715}*/
    8765 SCIP_CONSHDLRDATA* conshdlrdata;
    8766 int idx;
    8767
    8768 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
    8769 assert(conshdlrdata != NULL);
    8770
    8771 idx = ((int)(size_t)elem) - 1;
    8772 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
    8773
    8774 return (void*)&conshdlrdata->bilinterms[idx];
    8775}
    8776
    8777/** returns TRUE iff the bilinear term entries are equal */
    8778static
    8779SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
    8780{ /*lint --e{715}*/
    8783
    8784 /* get corresponding entries */
    8785 entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
    8786 entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
    8787 assert(entry1->x != NULL && entry1->y != NULL);
    8788 assert(entry2->x != NULL && entry2->y != NULL);
    8789 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
    8790 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
    8791
    8792 return entry1->x == entry2->x && entry1->y == entry2->y;
    8793}
    8794
    8795/** returns the hash value of the key */
    8796static
    8797SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
    8798{ /*lint --e{715}*/
    8800
    8801 entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
    8802 assert(entry->x != NULL && entry->y != NULL);
    8803 assert(SCIPvarCompare(entry->x, entry->y) < 1);
    8804
    8805 return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
    8806}
    8807
    8808/** compare two auxiliary expressions
    8809 *
    8810 * Compares auxiliary variables, followed by coefficients, and then constants.
    8811 */
    8812static
    8814{
    8817 int compvars;
    8818 int i;
    8819
    8820 /* compare the auxiliary variables */
    8821 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
    8822
    8823 if( compvars != 0 )
    8824 return compvars;
    8825
    8826 /* compare the coefficients and constants */
    8827 for( i = 0; i < 3; ++i )
    8828 {
    8829 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
    8830 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
    8831 }
    8832
    8833 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
    8834}
    8835
    8836/* add an auxiliary expression to a bilinear term */
    8837static
    8839 SCIP* scip, /**< SCIP data structure */
    8840 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
    8841 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
    8842 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
    8843 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
    8844 )
    8845{
    8846 SCIP_Bool found;
    8847 int pos;
    8848 int i;
    8849
    8850 *added = FALSE;
    8851
    8852 /* check if auxexpr has already been added to term */
    8853 if( term->nauxexprs == 0 )
    8854 {
    8855 found = FALSE;
    8856 pos = 0;
    8857 }
    8858 else
    8859 {
    8860 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
    8861 }
    8862
    8863 if( !found )
    8864 {
    8865 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
    8866 return SCIP_OKAY;
    8867
    8869 assert(term->auxexprssize >= term->nauxexprs + 1);
    8870
    8871 /* insert expression at the correct position */
    8872 for( i = term->nauxexprs; i > pos; --i )
    8873 {
    8874 term->aux.exprs[i] = term->aux.exprs[i-1];
    8875 }
    8876 term->aux.exprs[pos] = auxexpr;
    8877 ++(term->nauxexprs);
    8878 *added = TRUE;
    8879 }
    8880 else
    8881 {
    8882 assert(term->aux.exprs != NULL);
    8883 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
    8884 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
    8885 }
    8886
    8887 return SCIP_OKAY;
    8888}
    8889
    8890/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
    8891static
    8893 SCIP* scip, /**< SCIP data structure */
    8894 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8895 SCIP_CONS** conss, /**< nonlinear constraints */
    8896 int nconss /**< total number of nonlinear constraints */
    8897 )
    8898{
    8899 SCIP_CONSHDLRDATA* conshdlrdata;
    8900 SCIP_EXPRITER* it;
    8901 int c;
    8902
    8903 assert(conss != NULL || nconss == 0);
    8904
    8905 if( nconss == 0 )
    8906 return SCIP_OKAY;
    8907
    8908 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8909 assert(conshdlrdata != NULL);
    8910
    8911 /* check whether the bilinear terms have been stored already */
    8912 if( conshdlrdata->bilinterms != NULL )
    8913 return SCIP_OKAY;
    8914
    8915 /* create and initialize iterator */
    8919
    8920 /* iterate through all constraints */
    8921 for( c = 0; c < nconss; ++c )
    8922 {
    8923 SCIP_CONSDATA* consdata;
    8924 SCIP_EXPR* expr;
    8925
    8926 assert(conss != NULL && conss[c] != NULL);
    8927 consdata = SCIPconsGetData(conss[c]);
    8928 assert(consdata != NULL);
    8929
    8930 /* iterate through all expressions */
    8931 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    8932 {
    8933 SCIP_EXPR** children = SCIPexprGetChildren(expr);
    8934 SCIP_VAR* x = NULL;
    8935 SCIP_VAR* y = NULL;
    8936
    8937 /* check whether the expression is of the form f(..)^2 */
    8938 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
    8939 {
    8940 x = SCIPgetExprAuxVarNonlinear(children[0]);
    8941 y = x;
    8942 }
    8943 /* check whether the expression is of the form f(..) * g(..) */
    8944 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
    8945 {
    8946 x = SCIPgetExprAuxVarNonlinear(children[0]);
    8947 y = SCIPgetExprAuxVarNonlinear(children[1]);
    8948 }
    8949
    8950 /* add variables to the hash table */
    8951 if( x != NULL && y != NULL )
    8952 {
    8955 }
    8956 }
    8957 }
    8958
    8959 /* release iterator */
    8960 SCIPfreeExpriter(&it);
    8961
    8962 return SCIP_OKAY;
    8963}
    8964
    8965/** store x, y and the locks in a new bilinear term */
    8966static
    8968 SCIP* scip, /**< SCIP data structure */
    8969 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    8970 SCIP_VAR* x, /**< the first variable */
    8971 SCIP_VAR* y, /**< the second variable */
    8972 int nlockspos, /**< number of positive locks of the bilinear term */
    8973 int nlocksneg, /**< number of negative locks of the bilinear term */
    8974 int* idx, /**< pointer to store the position of the term in bilinterms array */
    8975 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
    8976 )
    8977{
    8978 SCIP_CONSHDLRDATA* conshdlrdata;
    8980
    8981 assert(conshdlr != NULL);
    8982 assert(x != NULL);
    8983 assert(y != NULL);
    8984 assert(nlockspos >= 0);
    8985 assert(nlocksneg >= 0);
    8986
    8987 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8988 assert(conshdlrdata != NULL);
    8989
    8990 /* ensure that x.index <= y.index */
    8991 if( SCIPvarCompare(x, y) == 1 )
    8992 {
    8993 SCIPswapPointers((void**)&x, (void**)&y);
    8994 }
    8995 assert(SCIPvarCompare(x, y) < 1);
    8996
    8997 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
    8998
    8999 /* update or create the term */
    9000 if( *idx >= 0 )
    9001 { /* the term has already been added */
    9002 assert(conshdlrdata->bilinterms[*idx].x == x);
    9003 assert(conshdlrdata->bilinterms[*idx].y == y);
    9004
    9005 /* get term and add locks */
    9006 term = &conshdlrdata->bilinterms[*idx];
    9007 assert(existing <= term->existing); /* implicit terms are added after existing ones */
    9008 term->nlockspos += nlockspos;
    9009 term->nlocksneg += nlocksneg;
    9010 }
    9011 else
    9012 { /* this is the first time we encounter this product */
    9013 /* ensure size of bilinterms array */
    9014 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
    9015
    9016 *idx = conshdlrdata->nbilinterms;
    9017
    9018 /* get term and set values in the created bilinear term */
    9019 term = &conshdlrdata->bilinterms[*idx];
    9020 assert(term != NULL);
    9021 term->x = x;
    9022 term->y = y;
    9023 term->nauxexprs = 0;
    9024 term->auxexprssize = 0;
    9025 term->nlockspos = nlockspos;
    9026 term->nlocksneg = nlocksneg;
    9027 term->existing = existing;
    9028 if( existing )
    9029 term->aux.var = NULL;
    9030 else
    9031 term->aux.exprs = NULL;
    9032
    9033 /* increase the total number of bilinear terms */
    9034 ++(conshdlrdata->nbilinterms);
    9035
    9036 /* save to the hashtable */
    9037 if( conshdlrdata->bilinhashtable == NULL )
    9038 {
    9039 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
    9040 bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
    9041 (void*)conshdlrdata) );
    9042 }
    9043 assert(conshdlrdata->bilinhashtable != NULL);
    9044
    9045 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
    9046 * because zero can not be inserted into hash table
    9047 */
    9048 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
    9049
    9050 /* capture product variables */
    9053 }
    9054
    9055 return SCIP_OKAY;
    9056}
    9057
    9058/** frees array of bilinear terms and hash table */
    9059static
    9061 SCIP* scip, /**< SCIP data structure */
    9062 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
    9063 )
    9064{
    9065 int i;
    9066 int j;
    9067
    9068 assert(conshdlrdata != NULL);
    9069
    9070 /* check whether bilinear terms have been stored */
    9071 if( conshdlrdata->bilinterms == NULL )
    9072 {
    9073 assert(conshdlrdata->bilinterms == NULL);
    9074 assert(conshdlrdata->nbilinterms == 0);
    9075 assert(conshdlrdata->bilintermssize == 0);
    9076
    9077 return SCIP_OKAY;
    9078 }
    9079
    9080 /* release variables */
    9081 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
    9082 {
    9083 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
    9084 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
    9085
    9086 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
    9087 {
    9088 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
    9089 {
    9090 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
    9091 }
    9092 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
    9093 }
    9094
    9095 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
    9096 {
    9097 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
    9098 continue;
    9099 }
    9100
    9101 /* the rest is for simple terms with a single auxvar */
    9102
    9103 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
    9104 if( conshdlrdata->bilinterms[i].aux.var != NULL )
    9105 {
    9106 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
    9107 }
    9108 }
    9109
    9110 /* free hash table */
    9111 if( conshdlrdata->bilinhashtable != NULL )
    9112 {
    9113 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
    9114 }
    9115
    9116 /* free bilinterms array; reset counters */
    9117 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
    9118 conshdlrdata->nbilinterms = 0;
    9119 conshdlrdata->bilintermssize = 0;
    9120
    9121 return SCIP_OKAY;
    9122}
    9123
    9124/*
    9125 * vertex polyhedral separation
    9126 */
    9127
    9128/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
    9129static
    9131 SCIP* scip, /**< SCIP data structure */
    9132 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
    9133 SCIP_LPI** lp /**< pointer to store created LP */
    9134 )
    9135{
    9136 SCIP_Real* obj;
    9137 SCIP_Real* lb;
    9138 SCIP_Real* ub;
    9139 SCIP_Real* val;
    9140 int* beg;
    9141 int* ind;
    9142 unsigned int nnonz;
    9143 unsigned int ncols;
    9144 unsigned int nrows;
    9145 unsigned int i;
    9146 unsigned int k;
    9147
    9148 assert(scip != NULL);
    9149 assert(lp != NULL);
    9150 assert(nvars > 0);
    9151 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
    9152
    9153 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
    9154
    9155 /* create lpi to store the LP */
    9157
    9158 nrows = (unsigned int)nvars + 1;
    9159 ncols = POWEROFTWO((unsigned int)nvars);
    9160 nnonz = (ncols * (nrows + 1)) / 2;
    9161
    9162 /* allocate necessary memory; set obj, lb, and ub to zero */
    9163 SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
    9165 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
    9166 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
    9167 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
    9168 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
    9169
    9170 /* calculate nonzero entries in the LP */
    9171 for( i = 0, k = 0; i < ncols; ++i )
    9172 {
    9173 int row;
    9174 unsigned int a;
    9175
    9176 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
    9177 ub[i] = SCIPlpiInfinity(*lp);
    9178
    9179 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
    9180 beg[i] = (int)k;
    9181 row = 0;
    9182
    9183 /* iterate through the bit representation of i */
    9184 a = 1;
    9185 while( a <= i )
    9186 {
    9187 if( (a & i) != 0 )
    9188 {
    9189 val[k] = 1.0;
    9190 ind[k] = row;
    9191
    9192 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
    9193
    9194 ++k;
    9195 }
    9196
    9197 a <<= 1;
    9198 ++row;
    9199 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
    9200 assert(POWEROFTWO(row) == a);
    9201 }
    9202
    9203 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
    9204 val[k] = 1.0;
    9205 ind[k] = (int)nrows - 1;
    9206 ++k;
    9207 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
    9208 }
    9209 assert(k == nnonz);
    9210
    9211 /* load all data into LP interface
    9212 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
    9213 */
    9214 assert(nrows <= ncols);
    9216 (int)ncols, obj, lb, ub, NULL,
    9217 (int)nrows, lb, lb, NULL,
    9218 (int)nnonz, beg, ind, val) );
    9219
    9220 /* for the last row, we can set the rhs to 1.0 already */
    9221 ind[0] = (int)nrows - 1;
    9222 val[0] = 1.0;
    9223 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
    9224
    9225 /* free allocated memory */
    9232
    9233 return SCIP_OKAY;
    9234}
    9235
    9236/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
    9237 * \max_{v \in V} f(v) - (\alpha v + \beta) \f$ (\f$\max_{v \in V} \alpha v + \beta - f(v) \f$) where \f$ V \f$ is the
    9238 * set of vertices of the domain
    9239 */
    9240static
    9242 SCIP* scip, /**< SCIP data structure */
    9243 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
    9244 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
    9245 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
    9246 int nallvars, /**< number of all variables */
    9247 int nvars, /**< number of unfixed variables */
    9248 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
    9249 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
    9250 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
    9251 )
    9252{
    9253 SCIP_Real maxerror;
    9254 SCIP_Real facetval;
    9255 SCIP_Real funval;
    9256 SCIP_Real error;
    9257 unsigned int i;
    9258 unsigned int ncorners;
    9259 unsigned int prev;
    9260
    9261 assert(scip != NULL);
    9262 assert(funvals != NULL);
    9263 assert(box != NULL);
    9264 assert(nonfixedpos != NULL);
    9265 assert(facetcoefs != NULL);
    9266
    9267 ncorners = POWEROFTWO(nvars);
    9268 maxerror = 0.0;
    9269
    9270 /* check the origin (all variables at lower bound) */
    9271 facetval = facetconstant;
    9272 for( i = 0; i < (unsigned int) nallvars; ++i )
    9273 facetval += facetcoefs[i] * box[2*i];
    9274
    9275 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
    9276 funval = funvals[0];
    9277 if( overestimate )
    9278 error = funval - facetval;
    9279 else
    9280 error = facetval - funval;
    9281
    9282 /* update maximum error */
    9283 maxerror = MAX(error, maxerror);
    9284
    9285 prev = 0;
    9286 for( i = 1; i < ncorners; ++i )
    9287 {
    9288 unsigned int gray;
    9289 unsigned int diff;
    9290 unsigned int pos;
    9291 int origpos;
    9292
    9293 gray = i ^ (i >> 1);
    9294 diff = gray ^ prev;
    9295
    9296 /* compute position of unique 1 of diff */
    9297 pos = 0;
    9298 while( (diff >>= 1) != 0 )
    9299 ++pos;
    9300 assert(pos < (unsigned int)nvars);
    9301
    9302 origpos = nonfixedpos[pos];
    9303
    9304 if( gray > prev )
    9305 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
    9306 else
    9307 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
    9308
    9309 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
    9310 funval = funvals[gray];
    9311 if( overestimate )
    9312 error = funval - facetval;
    9313 else
    9314 error = facetval - funval;
    9315
    9316 /* update maximum error */
    9317 maxerror = MAX(error, maxerror);
    9318
    9319 prev = gray;
    9320 }
    9321
    9322 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
    9323
    9324 return maxerror;
    9325}
    9326
    9327/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
    9328static
    9330 SCIP* scip, /**< SCIP data structure */
    9331 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    9332 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
    9333 SCIP_Real* xstar, /**< point to be separated */
    9334 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
    9335 int nallvars, /**< half of the length of box */
    9336 int* nonfixedpos, /**< indices of nonfixed variables */
    9337 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
    9338 int nvars, /**< number of nonfixed variables */
    9339 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
    9340 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
    9341 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
    9342 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
    9343 )
    9344{ /*lint --e{715}*/
    9345 SCIP_CONSHDLRDATA* conshdlrdata;
    9346 SCIP_LPI* lp;
    9347 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
    9348 int* inds;
    9349 int ncols;
    9350 int nrows;
    9351 int i;
    9352 SCIP_Real facetvalue;
    9353 SCIP_Real mindomwidth;
    9354 SCIP_RETCODE lpsolveretcode;
    9355
    9356 assert(scip != NULL);
    9357 assert(conshdlr != NULL);
    9358 assert(xstar != NULL);
    9359 assert(box != NULL);
    9360 assert(nonfixedpos != NULL);
    9361 assert(funvals != NULL);
    9362 assert(nvars >= 0);
    9363 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
    9364 assert(success != NULL);
    9365 assert(facetcoefs != NULL);
    9366 assert(facetconstant != NULL);
    9367
    9368 *success = FALSE;
    9369
    9370 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9371 assert(conshdlrdata != NULL);
    9372
    9373 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
    9374 {
    9375 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
    9376 }
    9377
    9378 /* construct an LP for this size, if not having one already */
    9379 if( conshdlrdata->vp_lp[nvars] == NULL )
    9380 {
    9381 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
    9382 }
    9383 lp = conshdlrdata->vp_lp[nvars];
    9384 assert(lp != NULL);
    9385
    9386 /* get number of cols and rows of separation lp */
    9387 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
    9388 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
    9389
    9390 /* number of columns should equal the number of corners = 2^nvars */
    9391 assert(ncols == (int)POWEROFTWO(nvars));
    9392
    9393 /* allocate necessary memory */
    9394 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
    9395 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
    9396
    9397 /*
    9398 * set up the described LP on the transformed space
    9399 */
    9400
    9401 for( i = 0; i < ncols; ++i )
    9402 inds[i] = i;
    9403
    9404 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
    9405 mindomwidth = 2*SCIPinfinity(scip);
    9406 for( i = 0; i < nrows-1; ++i )
    9407 {
    9408 SCIP_Real solval;
    9409 SCIP_Real lb;
    9410 SCIP_Real ub;
    9411 int varpos;
    9412
    9413 assert(i < nvars);
    9414
    9415 varpos = nonfixedpos[i];
    9416 lb = box[2 * varpos];
    9417 ub = box[2 * varpos + 1];
    9418 solval = xstar[varpos];
    9419
    9420 if( ub - lb < mindomwidth )
    9421 mindomwidth = ub - lb;
    9422
    9423 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
    9424 if( solval <= lb )
    9425 aux[i] = 0.0;
    9426 else if( solval >= ub )
    9427 aux[i] = 1.0;
    9428 else
    9429 aux[i] = (solval - lb) / (ub - lb);
    9430
    9431 /* perturb point to hopefully obtain a facet of the convex envelope */
    9432 if( conshdlrdata->vp_maxperturb > 0.0 )
    9433 {
    9434 assert(conshdlrdata->vp_randnumgen != NULL);
    9435
    9436 if( aux[i] == 1.0 )
    9437 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
    9438 else if( aux[i] == 0.0 )
    9439 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
    9440 else
    9441 {
    9442 SCIP_Real perturbation;
    9443
    9444 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
    9445 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
    9446 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
    9447 }
    9448 assert(0.0 < aux[i] && aux[i] < 1.0);
    9449 }
    9450
    9451 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
    9452 }
    9453
    9454 /* update LP */
    9455 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
    9456 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
    9458
    9459 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
    9460 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
    9461 {
    9462 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
    9463 }
    9464 /* set an iteration limit so we do not run forever */
    9466 /* since we work with the dual of the LP, primal feastol determines how much we want the computed facet to be the best possible one */
    9468 /* since we work with the dual of the LP, dual feastol determines validity of the facet
    9469 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
    9470 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
    9471 */
    9473
    9474#ifdef SCIP_DEBUG
    9476#endif
    9477
    9478 /*
    9479 * solve the LP and store the resulting facet for the transformed space
    9480 */
    9481 if( conshdlrdata->vp_dualsimplex )
    9482 {
    9483 lpsolveretcode = SCIPlpiSolveDual(lp);
    9484 }
    9485 else
    9486 {
    9487 lpsolveretcode = SCIPlpiSolvePrimal(lp);
    9488 }
    9489 if( lpsolveretcode == SCIP_LPERROR )
    9490 {
    9491 SCIPdebugMsg(scip, "LP error, aborting.\n");
    9492 goto CLEANUP;
    9493 }
    9494 SCIP_CALL( lpsolveretcode );
    9495
    9496 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
    9497 if( !SCIPlpiIsDualFeasible(lp) )
    9498 {
    9499 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
    9500 goto CLEANUP;
    9501 }
    9502
    9503 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
    9504 * columns than needed, in particular, \bar \beta is the last dual multiplier
    9505 */
    9506 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
    9507
    9508 for( i = 0; i < nvars; ++i )
    9509 facetcoefs[nonfixedpos[i]] = aux[i];
    9510 /* last dual multiplier is the constant */
    9511 *facetconstant = aux[nrows - 1];
    9512
    9513#ifdef SCIP_DEBUG
    9514 SCIPdebugMsg(scip, "facet for the transformed problem: ");
    9515 for( i = 0; i < nallvars; ++i )
    9516 {
    9517 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
    9518 }
    9519 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
    9520#endif
    9521
    9522 /*
    9523 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
    9524 */
    9525
    9526 SCIPdebugMsg(scip, "facet in orig. space: ");
    9527
    9528 facetvalue = 0.0;
    9529 for( i = 0; i < nvars; ++i )
    9530 {
    9531 SCIP_Real lb;
    9532 SCIP_Real ub;
    9533 int varpos;
    9534
    9535 varpos = nonfixedpos[i];
    9536 lb = box[2 * varpos];
    9537 ub = box[2 * varpos + 1];
    9538 assert(!SCIPisEQ(scip, lb, ub));
    9539
    9540 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
    9541 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
    9542
    9543 /* beta = beta_bar - sum_i alpha_i * lb_i */
    9544 *facetconstant -= facetcoefs[varpos] * lb;
    9545
    9546 /* evaluate */
    9547 facetvalue += facetcoefs[varpos] * xstar[varpos];
    9548
    9549 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
    9550 }
    9551 SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
    9552
    9553 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
    9554 facetvalue += *facetconstant;
    9555
    9556 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
    9557
    9558 /* if overestimate, then we want facetvalue < targetvalue
    9559 * if underestimate, then we want facetvalue > targetvalue
    9560 * if none holds, give up
    9561 * so maybe here we should check against the minimal violation
    9562 */
    9563 if( overestimate == (facetvalue > targetvalue) )
    9564 {
    9565 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
    9566 goto CLEANUP;
    9567 }
    9568
    9569 /* if we made it until here, then we have a nice facet */
    9570 *success = TRUE;
    9571
    9572CLEANUP:
    9573 /* free allocated memory */
    9574 SCIPfreeBufferArray(scip, &inds);
    9576
    9577 return SCIP_OKAY;
    9578}
    9579
    9580/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
    9581 *
    9582 * In other words, compute the line that passes through two given points.
    9583 */
    9584static
    9586 SCIP* scip, /**< SCIP data structure */
    9587 SCIP_Real left, /**< left coordinate */
    9588 SCIP_Real right, /**< right coordinate */
    9589 SCIP_Real funleft, /**< value of function in left coordinate */
    9590 SCIP_Real funright, /**< value of function in right coordinate */
    9591 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
    9592 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
    9593 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
    9594 )
    9595{
    9596 assert(scip != NULL);
    9597 assert(SCIPisLE(scip, left, right));
    9598 assert(!SCIPisInfinity(scip, -left));
    9599 assert(!SCIPisInfinity(scip, right));
    9600 assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
    9601 assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
    9602 assert(success != NULL);
    9603 assert(facetcoef != NULL);
    9604 assert(facetconstant != NULL);
    9605
    9606 *facetcoef = (funright - funleft) / (right - left);
    9607 *facetconstant = funleft - *facetcoef * left;
    9608
    9609 *success = TRUE;
    9610
    9611 return SCIP_OKAY;
    9612}
    9613
    9614/** given three points, constructs coefficient of equation for hyperplane generated by these three points
    9615 *
    9616 * Three points a, b, and c are given.
    9617 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
    9618 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
    9619 */
    9620static
    9622 SCIP* scip, /**< SCIP data structure */
    9623 SCIP_Real a1, /**< first coordinate of a */
    9624 SCIP_Real a2, /**< second coordinate of a */
    9625 SCIP_Real a3, /**< third coordinate of a */
    9626 SCIP_Real b1, /**< first coordinate of b */
    9627 SCIP_Real b2, /**< second coordinate of b */
    9628 SCIP_Real b3, /**< third coordinate of b */
    9629 SCIP_Real c1, /**< first coordinate of c */
    9630 SCIP_Real c2, /**< second coordinate of c */
    9631 SCIP_Real c3, /**< third coordinate of c */
    9632 SCIP_Real* alpha, /**< coefficient of first coordinate */
    9633 SCIP_Real* beta, /**< coefficient of second coordinate */
    9634 SCIP_Real* gamma_, /**< coefficient of third coordinate */
    9635 SCIP_Real* delta /**< constant right-hand side */
    9636 )
    9637{
    9638 assert(scip != NULL);
    9639 assert(alpha != NULL);
    9640 assert(beta != NULL);
    9641 assert(gamma_ != NULL);
    9642 assert(delta != NULL);
    9643
    9644 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
    9645 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
    9646 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
    9647 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
    9648
    9649 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
    9650
    9651 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
    9652 SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
    9653 SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
    9654 {
    9655 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
    9656 *delta = 0.0;
    9657 *alpha = 0.0;
    9658 *beta = 0.0;
    9659 *gamma_ = 0.0;
    9660 return SCIP_OKAY;
    9661 }
    9662
    9663 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
    9664 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
    9665 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
    9666 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
    9667 {
    9668 SCIP_Real m[9];
    9669 SCIP_Real rhs[3];
    9670 SCIP_Real x[3];
    9671 SCIP_Bool success;
    9672
    9673 /*
    9674 SCIPdebugMsg(scip, "a = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", a1, a2, a3, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3, SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3));
    9675 SCIPdebugMsg(scip, "b = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", b1, b2, b3, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3, SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3));
    9676 SCIPdebugMsg(scip, "c = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", c1, c2, c3, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3, SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3));
    9677 */
    9678
    9679 /* initialize matrix column-wise */
    9680 m[0] = a1;
    9681 m[1] = b1;
    9682 m[2] = c1;
    9683 m[3] = a2;
    9684 m[4] = b2;
    9685 m[5] = c2;
    9686 m[6] = a3;
    9687 m[7] = b3;
    9688 m[8] = c3;
    9689
    9690 rhs[0] = 1.0;
    9691 rhs[1] = 1.0;
    9692 rhs[2] = 1.0;
    9693
    9694 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
    9695
    9696 /* solve the linear problem */
    9697 SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
    9698
    9699 *delta = rhs[0];
    9700 *alpha = x[0];
    9701 *beta = x[1];
    9702 *gamma_ = x[2];
    9703
    9704 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
    9705 * not add a cut to SCIP and that all assertions are trivially fulfilled
    9706 */
    9707 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
    9708 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
    9709 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
    9710 {
    9711 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
    9712 *delta = 0.0;
    9713 *alpha = 0.0;
    9714 *beta = 0.0;
    9715 *gamma_ = 0.0;
    9716 }
    9717 }
    9718
    9719 if( *gamma_ < 0.0 )
    9720 {
    9721 *alpha = -*alpha;
    9722 *beta = -*beta;
    9723 *gamma_ = -*gamma_;
    9724 *delta = -*delta;
    9725 }
    9726
    9727 return SCIP_OKAY;
    9728}
    9729
    9730/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
    9731static
    9733 SCIP* scip, /**< SCIP data structure */
    9734 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
    9735 SCIP_Real p1[2], /**< first vertex of box */
    9736 SCIP_Real p2[2], /**< second vertex of box */
    9737 SCIP_Real p3[2], /**< third vertex of box */
    9738 SCIP_Real p4[2], /**< forth vertex of box */
    9739 SCIP_Real p1val, /**< value in p1 */
    9740 SCIP_Real p2val, /**< value in p2 */
    9741 SCIP_Real p3val, /**< value in p3 */
    9742 SCIP_Real p4val, /**< value in p4 */
    9743 SCIP_Real xstar[2], /**< point to be separated */
    9744 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
    9745 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
    9746 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
    9747 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
    9748 )
    9749{
    9750 SCIP_Real alpha, beta, gamma_, delta;
    9751 SCIP_Real xstarval, candxstarval = 0.0;
    9752 int leaveout;
    9753
    9754 assert(scip != NULL);
    9755 assert(success != NULL);
    9756 assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
    9757 assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
    9758 assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
    9759 assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
    9760 assert(facetcoefs != NULL);
    9761 assert(facetconstant != NULL);
    9762
    9763 *success = FALSE;
    9764
    9765 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
    9766 if( !overestimate )
    9767 {
    9768 p1val = -p1val;
    9769 p2val = -p2val;
    9770 p3val = -p3val;
    9771 p4val = -p4val;
    9772 targetvalue = -targetvalue;
    9773 }
    9774
    9775 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
    9776 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
    9777 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
    9778 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
    9779
    9780 /* Compute coefficients alpha, beta, gamma (>0), delta such that
    9781 * alpha*x + beta*y + gamma*z = delta
    9782 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
    9783 * the fourth corner point lies below this hyperplane.
    9784 * Since we assume that f is vertex-polyhedral, we then know that all points (x,y,f(x,y)) are below this hyperplane, i.e.,
    9785 * alpha*x + beta*y - delta <= -gamma * f(x,y),
    9786 * or, equivalently,
    9787 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
    9788 */
    9789 for( leaveout = 1; leaveout <= 4; ++leaveout )
    9790 {
    9791 switch( leaveout)
    9792 {
    9793 case 1 :
    9794 /* get hyperplane through p2, p3, p4 */
    9795 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
    9796 &alpha, &beta, &gamma_, &delta) );
    9797 /* if not underestimating in p1, then go to next candidate */
    9798 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
    9799 continue;
    9800 break;
    9801
    9802 case 2 :
    9803 /* get hyperplane through p1, p3, p4 */
    9804 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
    9805 &alpha, &beta, &gamma_, &delta) );
    9806 /* if not underestimating in p2, then go to next candidate */
    9807 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
    9808 continue;
    9809 break;
    9810
    9811 case 3 :
    9812 /* get hyperplane through p1, p2, p4 */
    9813 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
    9814 &alpha, &beta, &gamma_, &delta) );
    9815 /* if not underestimating in p3, then go to next candidate */
    9816 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
    9817 continue;
    9818 break;
    9819
    9820 case 4 :
    9821 /* get hyperplane through p1, p2, p3 */
    9822 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
    9823 &alpha, &beta, &gamma_, &delta) );
    9824 /* if not underestimating in p4, then stop */
    9825 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
    9826 continue;
    9827 break;
    9828
    9829 default: /* only for lint */
    9830 alpha = SCIP_INVALID;
    9831 beta = SCIP_INVALID;
    9832 gamma_ = SCIP_INVALID;
    9833 delta = SCIP_INVALID;
    9834 break;
    9835 }
    9836
    9837 /* check if bad luck: should not happen if numerics are fine */
    9838 if( SCIPisZero(scip, gamma_) )
    9839 continue;
    9840 assert(!SCIPisNegative(scip, gamma_));
    9841
    9842 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
    9843 if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
    9844 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
    9845 continue;
    9846
    9847 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
    9848
    9849 /* value of hyperplane candidate in xstar */
    9850 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
    9851
    9852 /* if reaching target and first or better than previous candidate, then update */
    9853 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
    9854 {
    9855 /* flip hyperplane */
    9856 if( !overestimate )
    9857 gamma_ = -gamma_;
    9858
    9859 facetcoefs[0] = -alpha/gamma_;
    9860 facetcoefs[1] = -beta/gamma_;
    9861 *facetconstant = delta/gamma_;
    9862
    9863 *success = TRUE;
    9864 candxstarval = xstarval;
    9865 }
    9866 }
    9867
    9868 return SCIP_OKAY;
    9869}
    9870
    9871/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
    9872 * graph yet) in an array
    9873 */
    9874static
    9876 SCIP* scip, /**< SCIP pointer */
    9877 int** openidx, /**< address of openidx array */
    9878 int nelems, /**< number of elements that need to be stored */
    9879 int* maxnelems /**< pointer to store maximum number that can be stored */
    9880 )
    9881{
    9882 assert(scip != NULL);
    9883 assert(openidx != NULL);
    9884 assert(maxnelems != NULL);
    9885
    9886 if( nelems > *maxnelems )
    9887 {
    9888 int newsize;
    9889
    9890 newsize = SCIPcalcMemGrowSize(scip, nelems);
    9891 assert(newsize >= nelems);
    9892
    9893 SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
    9894
    9895 *maxnelems = newsize;
    9896 }
    9897
    9898 return SCIP_OKAY;
    9899}
    9900
    9901/** ensures that we can store information about local variables in an array */
    9902static
    9904 SCIP* scip, /**< SCIP pointer */
    9905 SCIP_VAR*** vars, /**< address of variable array */
    9906 SCIP_Real** vals, /**< address of value array */
    9907 int nelems, /**< number of elements that need to be stored */
    9908 int* maxnelems /**< pointer to store maximum number that can be stored */
    9909 )
    9910{
    9911 assert(scip != NULL);
    9912 assert(vars != NULL);
    9913 assert(vals != NULL);
    9914 assert(maxnelems != NULL);
    9915
    9916 if( nelems > *maxnelems )
    9917 {
    9918 int newsize;
    9919
    9920 newsize = SCIPcalcMemGrowSize(scip, nelems);
    9921 assert(newsize > *maxnelems);
    9922
    9923 SCIP_CALL( SCIPreallocBufferArray(scip, vars, newsize) );
    9924 SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
    9925
    9926 *maxnelems = newsize;
    9927 }
    9928
    9929 return SCIP_OKAY;
    9930}
    9931
    9932/** tries to add gadget for finding signed permutations of bilinear products
    9933 *
    9934 * If a product has exactly two children being variables, negating both simultanteoulsy
    9935 * is a signed permutation.
    9936 */
    9937static
    9939 SCIP* scip, /**< SCIP pointer */
    9940 SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
    9941 SCIP_CONS* cons, /**< constraint containing product expression */
    9942 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    9943 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
    9944 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
    9945 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
    9946 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    9947 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    9948 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    9949 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
    9950 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
    9951 )
    9952{
    9953 SYM_EXPRDATA* symdata;
    9954 SCIP_EXPR** children;
    9955 SCIP_VAR* var1 = NULL;
    9956 SCIP_VAR* var2 = NULL;
    9957 SCIP_Real val1 = 0.0;
    9958 SCIP_Real val2 = 0.0;
    9959 SCIP_Real coef;
    9960 SCIP_Real prodval;
    9961 SCIP_Real constant;
    9962 int nlocvars;
    9963 int optype;
    9964 int nchildren;
    9965 int prodidx;
    9966 int coefidx1;
    9967 int coefidx2;
    9968 int childidx;
    9969
    9970 assert(scip != NULL);
    9971 assert(expr != NULL);
    9972 assert(SCIPisExprProduct(scip, expr));
    9973 assert(graph != NULL);
    9974 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
    9975 assert(consvars != NULL);
    9976 assert(consvals != NULL);
    9977 assert(maxnconsvars != NULL);
    9978 assert(*maxnconsvars > 0);
    9979 assert(handledexprs != NULL);
    9980 assert(success != NULL);
    9981
    9982 *success = FALSE;
    9983
    9984 /* we require exactly two children being variables */
    9985 nchildren = SCIPexprGetNChildren(expr);
    9986 if( nchildren != 2 )
    9987 return SCIP_OKAY;
    9988
    9989 children = SCIPexprGetChildren(expr);
    9990 if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
    9991 return SCIP_OKAY;
    9992
    9993 /* check whether each child is not multi-aggregated and is not shifted */
    9994 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
    9995
    9996 for( childidx = 0; childidx < 2; ++childidx )
    9997 {
    9998 (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
    9999 (*consvals)[0] = 1.0;
    10000 nlocvars = 1;
    10001 constant = 0.0;
    10002
    10003 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
    10004 &constant, SCIPconsIsTransformed(cons)) );
    10005
    10006 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
    10007 return SCIP_OKAY;
    10008
    10009 if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
    10010 != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
    10011 return SCIP_OKAY;
    10012
    10013 /* store information about variables */
    10014 if( childidx == 0 )
    10015 {
    10016 var1 = (*consvars)[0];
    10017 val1 = (*consvals)[0];
    10018 }
    10019 else
    10020 {
    10021 var2 = (*consvars)[0];
    10022 val2 = (*consvals)[0];
    10023 }
    10024 }
    10025 assert(var1 != NULL);
    10026 assert(var2 != NULL);
    10027
    10028 /* store the we handle the children */
    10029 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
    10030 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
    10031
    10032 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
    10033 assert(symdata != NULL);
    10034 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
    10035
    10036 coef = SCIPgetSymExprdataConstants(symdata)[0];
    10037
    10038 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
    10039
    10040 /* add gadget modeling the product
    10041 *
    10042 * Since the constants are 0, each variable is centered at the origin, which leads to
    10043 * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
    10044 * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
    10045 * negate both variables simulataneously.
    10046 */
    10048 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
    10049 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
    10050
    10051 prodval = coef * val1 * val2;
    10052
    10053 /* introduce nodes for the product value and its negation; since flipping both variables
    10054 * simultaneously is a signed symmetry, assign both nodes the same value
    10055 */
    10056 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
    10057 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
    10058
    10059 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
    10060 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
    10061 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
    10062
    10063 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
    10064 SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
    10065 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
    10066 SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
    10067 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
    10068 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
    10069 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
    10070 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
    10071
    10072 *success = TRUE;
    10073
    10074 return SCIP_OKAY;
    10075}
    10076
    10077/** returns whether an operator is even and, if yes, stores data about operator */
    10078static
    10080 SCIP* scip, /**< SCIP pointer */
    10081 SCIP_EXPR* expr, /**< expression corresponding to operator */
    10082 SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
    10083 * needed for symmetry computation */
    10084 SCIP_Real* value /**< pointer to store value for symmetry computation */
    10085 )
    10086{
    10087 SYM_EXPRDATA* symdata;
    10088
    10089 assert(scip != NULL);
    10090 assert(expr != NULL);
    10091 assert(hasvalue != NULL);
    10092 assert(value != NULL);
    10093
    10094 /* check for different operators known to be even */
    10095 if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
    10096 {
    10097 /* get remaining information needed for symmetry detection */
    10098 if( SCIPisExprSignpower(scip, expr) )
    10099 {
    10100 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
    10101 assert(symdata != NULL);
    10102 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
    10103
    10104 *value = SCIPgetSymExprdataConstants(symdata)[0];
    10105 *hasvalue = !SCIPisEQ(scip, *value, 1.0);
    10106
    10108 }
    10109 else
    10110 {
    10111 assert(SCIPisExprCos(scip, expr));
    10112 *hasvalue = FALSE;
    10113 }
    10114
    10115 return TRUE;
    10116 }
    10117 else if( SCIPisExprPower(scip, expr) )
    10118 {
    10119 SCIP_Real exponent;
    10120 int safeexponent;
    10121
    10122 /* only consider expressions corresponding to an even power */
    10123 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
    10124 assert(symdata != NULL);
    10125 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
    10126
    10127 exponent = SCIPgetSymExprdataConstants(symdata)[0];
    10129
    10130 /* check whether the exponent is an even integer */
    10131 if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
    10132 return FALSE;
    10133
    10134 /* deal with numerics */
    10135 safeexponent = (int) (exponent + 0.5);
    10136 if( safeexponent % 2 != 0 )
    10137 return FALSE;
    10138
    10139 *hasvalue = TRUE;
    10140 *value = exponent;
    10141
    10142 return TRUE;
    10143 }
    10144 else if( SCIPisExprAbs(scip, expr) )
    10145 {
    10146 *hasvalue = FALSE;
    10147
    10148 return TRUE;
    10149 }
    10150
    10151 return FALSE;
    10152}
    10153
    10154/** returns whether a variable is centered at 0 */
    10155static
    10157 SCIP* scip, /**< SCIP pointer */
    10158 SCIP_VAR* var /**< variable to be checked */
    10159 )
    10160{
    10161 assert(scip != NULL);
    10162 assert(var != NULL);
    10163
    10165 return FALSE;
    10166
    10168 return TRUE;
    10169
    10171 return TRUE;
    10172
    10173 return FALSE;
    10174}
    10175
    10176/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
    10177static
    10179 SCIP* scip, /**< SCIP pointer */
    10180 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
    10181 SCIP_EXPR* child, /**< child expression of evenopexpr */
    10182 SCIP_CONS* cons, /**< constraint containing expression */
    10183 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    10184 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
    10185 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
    10186 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
    10187 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
    10188 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
    10189 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    10190 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    10191 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    10192 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
    10193 )
    10194{
    10195 SCIP_VAR* var;
    10196 SCIP_Real constant;
    10197 SCIP_Real edgeweight;
    10198 int nlocvars;
    10199 int nodeidx;
    10200 int optype;
    10201 int thisopidx;
    10202
    10203 assert(scip != NULL);
    10204 assert(evenopexpr != NULL);
    10205 assert(child != NULL);
    10206 assert(SCIPisExprVar(scip, child));
    10207 assert(cons != NULL);
    10208 assert(graph != NULL);
    10209 assert(parentidx >= 0);
    10210 assert(consvars != NULL);
    10211 assert(consvals != NULL);
    10212 assert(maxnconsvars != NULL);
    10213 assert(success != NULL);
    10214
    10215 *success = FALSE;
    10216
    10217 /* check whether child variable is (multi-)aggregated */
    10218 var = SCIPgetVarExprVar(child);
    10219 (*consvars)[0] = var;
    10220 (*consvals)[0] = 1.0;
    10221 constant = 0.0;
    10222 nlocvars = 1;
    10223
    10224 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
    10225 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
    10226 SCIPconsIsTransformed(cons)) );
    10227
    10228 /* skip multi-aggregated variables or variables with domain not centered at 0 */
    10229 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
    10230 return SCIP_OKAY;
    10231
    10232 if( !varIsCenteredAt0(scip, var) )
    10233 return SCIP_OKAY;
    10234
    10235 /* store partial information for gadget */
    10236 var = (*consvars)[0];
    10237 edgeweight = (*consvals)[0];
    10238
    10239 /* add gadget to graph for even univariate expression */
    10240 *success = TRUE;
    10241
    10243
    10244 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
    10245 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
    10246
    10247 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
    10248 TRUE, edgeweight) );
    10250 TRUE, edgeweight) );
    10251
    10252 if( hassymval )
    10253 {
    10254 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
    10255 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
    10256 }
    10257
    10258 return SCIP_OKAY;
    10259}
    10260
    10261/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
    10262static
    10264 SCIP* scip, /**< SCIP pointer */
    10265 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
    10266 SCIP_EXPR* child, /**< child expression of evenopexpr */
    10267 SCIP_CONS* cons, /**< constraint containing expression */
    10268 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    10269 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
    10270 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
    10271 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
    10272 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
    10273 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
    10274 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    10275 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    10276 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    10277 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
    10278 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
    10279 )
    10280{
    10281 SCIP_VAR* var;
    10282 SCIP_Real constant;
    10283 SCIP_Real weight;
    10284 int nlocvars;
    10285 int nodeidx;
    10286 int optype;
    10287 int thisopidx;
    10288 int i;
    10289
    10290 assert(scip != NULL);
    10291 assert(evenopexpr != NULL);
    10292 assert(child != NULL);
    10293 assert(SCIPisExprSum(scip, child));
    10294 assert(cons != NULL);
    10295 assert(graph != NULL);
    10296 assert(parentidx >= 0);
    10297 assert(consvars != NULL);
    10298 assert(consvals != NULL);
    10299 assert(maxnconsvars != NULL);
    10300 assert(handledexprs != NULL);
    10301 assert(success != NULL);
    10302
    10303 *success = FALSE;
    10304
    10305 /* check whether child variable is (multi-)aggregated and whether all children are variables */
    10306 nlocvars = SCIPexprGetNChildren(child);
    10307
    10308 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
    10309
    10310 for( i = 0; i < nlocvars; ++i)
    10311 {
    10312 if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
    10313 {
    10314 (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
    10315 (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
    10316 }
    10317 else
    10318 return SCIP_OKAY;
    10319 }
    10320 constant = SCIPgetConstantExprSum(child);
    10321
    10322 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
    10323 SCIPconsIsTransformed(cons)) );
    10324
    10325 /* we can only handle the case without constant and two variables with domain centered at origin */
    10326 if( nlocvars > 2 || !SCIPisZero(scip, constant) )
    10327 return SCIP_OKAY;
    10328 assert(nlocvars > 0);
    10329
    10330 var = (*consvars)[0];
    10331 if( !varIsCenteredAt0(scip, var) )
    10332 return SCIP_OKAY;
    10333
    10334 if( nlocvars == 2 )
    10335 {
    10336 var = (*consvars)[1];
    10337 if( !varIsCenteredAt0(scip, var) )
    10338 return SCIP_OKAY;
    10339 }
    10340
    10341 /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
    10342 *success = TRUE;
    10343 for( i = 0; i < SCIPexprGetNChildren(child); ++i )
    10344 {
    10345 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
    10346 }
    10347
    10349
    10350 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
    10351 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
    10352
    10353 if( hassymval )
    10354 {
    10355 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
    10356 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
    10357 }
    10358
    10359 if( nlocvars == 1 )
    10360 {
    10361 var = (*consvars)[0];
    10362 weight = (*consvals)[0];
    10363
    10364 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
    10365 TRUE, weight) );
    10367 TRUE, weight) );
    10368 }
    10369 else
    10370 {
    10371 int dummyidx1;
    10372 int dummyidx2;
    10373
    10374 /* add dummy nodes for gadget */
    10375 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
    10376 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
    10377
    10378 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
    10379 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
    10380 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
    10381
    10382 /* connect dummy nodes with variables */
    10383 for( i = 0; i < 2; ++i)
    10384 {
    10385 var = (*consvars)[i];
    10386 weight = ABS((*consvals)[i]);
    10387
    10388 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, SCIPgetSymgraphVarnodeidx(scip, graph, var),
    10389 TRUE, weight) );
    10391 TRUE, weight) );
    10392 }
    10393 }
    10394
    10395 return SCIP_OKAY;
    10396}
    10397
    10398/** tries to add gadget for finding signed permutations of even univariate operators
    10399 *
    10400 * We handle two cases. First, if a univariate operator is even and has a variable
    10401 * as child, negating the child is signed permutation. Second, the univariate operator
    10402 * is even and has a weighted sum of two variables as child.
    10403 */
    10404static
    10406 SCIP* scip, /**< SCIP pointer */
    10407 SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
    10408 SCIP_CONS* cons, /**< constraint containing expression */
    10409 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    10410 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
    10411 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
    10412 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
    10413 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    10414 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    10415 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    10416 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
    10417 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
    10418 )
    10419{
    10420 SCIP_EXPR* child;
    10421 SCIP_Real val = 0.0;
    10422 SCIP_Bool hasval = FALSE;
    10423
    10424 assert(scip != NULL);
    10425 assert(expr != NULL);
    10426 assert(graph != NULL);
    10427 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
    10428 assert(consvars != NULL);
    10429 assert(consvals != NULL);
    10430 assert(maxnconsvars != NULL);
    10431 assert(*maxnconsvars > 0);
    10432 assert(handledexprs != NULL);
    10433 assert(success != NULL);
    10434
    10435 *success = FALSE;
    10436
    10437 /* ignore variable or value expressions */
    10438 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
    10439 return SCIP_OKAY;
    10440 assert(SCIPexprGetNChildren(expr) > 0);
    10441
    10442 /* ignore operators with too many children */
    10443 if( SCIPexprGetNChildren(expr) > 1 )
    10444 return SCIP_OKAY;
    10445
    10446 /* check whether operator is even */
    10447 if( !isEvenOperator(scip, expr, &hasval, &val) )
    10448 return SCIP_OKAY;
    10449
    10450 /* we can only treat the operator if its child is a variable or a sum */
    10451 child = SCIPexprGetChildren(expr)[0];
    10452 if( SCIPisExprVar(scip, child) )
    10453 {
    10454 SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
    10455 hasval, val, consvars, consvals, maxnconsvars, success) );
    10456 }
    10457 else if( SCIPisExprSum(scip, child) )
    10458 {
    10459 SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
    10460 hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
    10461 }
    10462
    10463 if( *success )
    10464 {
    10465 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
    10466 }
    10467
    10468 return SCIP_OKAY;
    10469}
    10470
    10471/** compares two variable pointers */
    10472static
    10474{ /*lint --e{715}*/
    10475 SCIP_VAR** vars;
    10476 SCIP_VAR* var1;
    10477 SCIP_VAR* var2;
    10478
    10479 vars = (SCIP_VAR**) dataptr;
    10480
    10481 var1 = vars[ind1];
    10482 var2 = vars[ind2];
    10483 assert(var1 != NULL);
    10484 assert(var2 != NULL);
    10485
    10486 /* sort variables by their unique index */
    10487 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
    10488 return -1;
    10489 if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
    10490 return 1;
    10491
    10492 return 0;
    10493}
    10494
    10495/** gets domain center of a variable which has not semi-infinite domain */
    10496static
    10498 SCIP* scip, /**< SCIP pointer */
    10499 SCIP_VAR* var /**< variable */
    10500 )
    10501{
    10502 SCIP_Real ub;
    10503 SCIP_Real lb;
    10504
    10505 ub = SCIPvarGetUbGlobal(var);
    10506 lb = SCIPvarGetLbGlobal(var);
    10507
    10508 assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
    10509
    10510 if ( SCIPisInfinity(scip, ub) )
    10511 return 0.0;
    10512
    10513 return (ub + lb) / 2;
    10514}
    10515
    10516/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
    10517static
    10519 SCIP* scip, /**< SCIP pointer */
    10520 SCIP_EXPR* sumexpr, /**< sum expression */
    10521 SCIP_CONS* cons, /**< constraint containing the sum expression */
    10522 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    10523 int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
    10524 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    10525 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    10526 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    10527 SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
    10528 )
    10529{
    10530 SYM_EXPRDATA* symdata;
    10531 SCIP_EXPR** children;
    10532 SCIP_EXPR** powexprs;
    10533 SCIP_EXPR** prodexprs;
    10534 SCIP_EXPR* child;
    10535 SCIP_VAR** powvars;
    10536 SCIP_VAR** prodvars;
    10537 SCIP_VAR* actvar;
    10538 SCIP_VAR* actvar2;
    10539 SCIP_VAR* var;
    10540 SCIP_VAR* var2;
    10541 SCIP_Real* sumcoefs;
    10542 SCIP_Real constant;
    10543 SCIP_Real constant2;
    10544 SCIP_Real val;
    10545 SCIP_Real val2;
    10546 SCIP_Bool* powexprused = NULL;
    10547 int* powperm = NULL;
    10548 int* prodperm = NULL;
    10549 int nchildren;
    10550 int nlocvars;
    10551 int nodeidx;
    10552 int coefnodeidx1;
    10553 int coefnodeidx2;
    10554 int cnt;
    10555 int i;
    10556 int j;
    10557 int nterms;
    10558 int npowexprs = 0;
    10559 int nprodexprs = 0;
    10560 int powcoef = 0;
    10561
    10562 assert(scip != NULL);
    10563 assert(sumexpr != NULL);
    10564 assert(cons != NULL);
    10565 assert(SCIPisExprSum(scip, sumexpr));
    10566 assert(consvars != NULL);
    10567 assert(consvals != NULL);
    10568 assert(maxnconsvars != NULL);
    10569 assert(*maxnconsvars > 0);
    10570 assert(handledexprs != NULL);
    10571
    10572 /* iterate over sum expression and extract all power and product expressions */
    10573 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
    10574 children = SCIPexprGetChildren(sumexpr);
    10575 nchildren = SCIPexprGetNChildren(sumexpr);
    10576 SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
    10577 SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
    10578 SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
    10579 SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
    10580
    10581 /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
    10582 /** @todo make this work in a more general case */
    10583 for( i = 0; i < nchildren; ++i )
    10584 {
    10585 if( SCIPisExprPower(scip, children[i]) )
    10586 {
    10587 SCIP_Real exponent;
    10588
    10589 /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
    10590 if( powcoef == 0 )
    10591 {
    10592 if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
    10593 powcoef = (int) SCIPround(scip, sumcoefs[i]);
    10594 }
    10595 else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
    10596 continue;
    10597
    10598 /* we only store power expressions if their child is a variable */
    10599 assert(SCIPexprGetNChildren(children[i]) == 1);
    10600 child = SCIPexprGetChildren(children[i])[0];
    10601 if( !SCIPisExprVar(scip, child) )
    10602 continue;
    10603
    10604 /* the power is required to be a 2 */
    10605 SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
    10606 assert(symdata != NULL);
    10607 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
    10608
    10609 exponent = SCIPgetSymExprdataConstants(symdata)[0];
    10610 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
    10611
    10612 if( !SCIPisEQ(scip, exponent, 2.0) )
    10613 continue;
    10614
    10615 /* we only store power expressions if the child is not multi-aggregated */
    10616 var = SCIPgetVarExprVar(child);
    10618 {
    10619 powexprs[npowexprs] = children[i];
    10620 powvars[npowexprs++] = var;
    10621 }
    10622 }
    10623 else if( SCIPisExprProduct(scip, children[i]) )
    10624 {
    10625 /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
    10626 if( powcoef == 0 )
    10627 {
    10628 if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
    10629 powcoef = (int) -SCIPround(scip, sumcoefs[i]);
    10630 }
    10631 else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
    10632 continue;
    10633
    10634 /* we only store power expressions if they have exactly two children being variables */
    10635 if( SCIPexprGetNChildren(children[i]) != 2 )
    10636 continue;
    10637 if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
    10638 || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
    10639 continue;
    10640
    10641 var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
    10642 var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
    10643
    10644 /* we only store product expressions if the children are not multi-aggregated */
    10647 {
    10648 prodexprs[nprodexprs] = children[i];
    10649 prodvars[nprodexprs++] = var;
    10650 prodexprs[nprodexprs] = children[i];
    10651 prodvars[nprodexprs++] = var2;
    10652 }
    10653 }
    10654 }
    10655
    10656 if( npowexprs == 0 || nprodexprs != npowexprs )
    10657 goto FREEMEMORY;
    10658
    10659 /* check whether the power variables and product variables match */
    10660 SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
    10661 SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
    10662
    10663 SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
    10664 SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
    10665
    10666 for( i = 0; i < npowexprs; ++i )
    10667 {
    10668 if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
    10669 goto FREEMEMORY;
    10670 }
    10671
    10672 /* if we reach this line, the variables match: we have found a potential norm constraint */
    10673 assert(npowexprs % 2 == 0);
    10674 nterms = npowexprs / 2;
    10675 SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
    10676
    10677 /* add gadget of each squared difference term */
    10678 cnt = 0;
    10679 for( i = 0; i < nterms; ++i )
    10680 {
    10681 SCIP_Bool var1found = FALSE;
    10682 SCIP_Bool var2found = FALSE;
    10683
    10684 (*consvals)[0] = 1.0;
    10685 (*consvars)[0] = prodvars[cnt++];
    10686 constant = 0.0;
    10687 nlocvars = 1;
    10688
    10690 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
    10691
    10692 if( nlocvars != 1 )
    10693 {
    10694 ++cnt;
    10695 continue;
    10696 }
    10697 actvar = (*consvars)[0];
    10698 val = (*consvals)[0];
    10699
    10700 (*consvals)[0] = 1.0;
    10701 (*consvars)[0] = prodvars[cnt++];
    10702 constant2 = 0.0;
    10703 nlocvars = 1;
    10704
    10706 &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
    10707
    10708 if( nlocvars != 1 )
    10709 continue;
    10710 actvar2 = (*consvars)[0];
    10711 val2 = (*consvals)[0];
    10712
    10713 /* we cannot handle the pair of variables if their constant/scalar differs or one variable
    10714 * cannot be centered at the origin or they are not centered around the same point
    10715 */
    10716 if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
    10720 || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
    10721 continue;
    10722
    10723 /* add gadget */
    10724 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
    10725 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
    10726 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
    10727
    10728 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
    10729 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
    10730 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
    10731 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
    10732 SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
    10733 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
    10734 SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
    10735 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
    10736 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
    10737 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
    10738 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
    10739
    10740 /* mark product expression as handled */
    10741 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
    10742
    10743 /* find corresponding unused power expressions and mark them as handled */
    10744 for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
    10745 {
    10746 if( powexprused[j] )
    10747 continue;
    10748 assert(cnt >= 2);
    10749
    10750 if( !var1found && powvars[j] == prodvars[cnt - 2] )
    10751 {
    10752 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
    10753 powexprused[j] = TRUE;
    10754 var1found = TRUE;
    10755 }
    10756 else if( !var2found && powvars[j] == prodvars[cnt - 1] )
    10757 {
    10758 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
    10759 powexprused[j] = TRUE;
    10760 var2found = TRUE;
    10761 }
    10762 }
    10763 }
    10764
    10765 FREEMEMORY:
    10766 SCIPfreeBufferArrayNull(scip, &powexprused);
    10767 SCIPfreeBufferArrayNull(scip, &prodperm);
    10768 SCIPfreeBufferArrayNull(scip, &powperm);
    10769 SCIPfreeBufferArray(scip, &prodvars);
    10770 SCIPfreeBufferArray(scip, &powvars);
    10771 SCIPfreeBufferArray(scip, &prodexprs);
    10772 SCIPfreeBufferArray(scip, &powexprs);
    10773
    10774 return SCIP_OKAY;
    10775}
    10776
    10777/** adds symmetry information of constraint to a symmetry detection graph */
    10778static
    10780 SCIP* scip, /**< SCIP pointer */
    10781 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
    10782 SCIP_CONS* cons, /**< constraint */
    10783 SYM_GRAPH* graph, /**< symmetry detection graph */
    10784 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
    10785 )
    10786{ /*lint --e{850}*/
    10787 SCIP_EXPRITER* it;
    10788 SCIP_HASHSET* handledexprs;
    10789 SCIP_EXPR* rootexpr;
    10790 SCIP_EXPR* expr;
    10791 SCIP_VAR** consvars;
    10792 SCIP_Real* consvals;
    10793 SCIP_Real constant;
    10794 SCIP_Real parentcoef = 0.0;
    10795 int* openidx;
    10796 int maxnopenidx;
    10797 int parentidx;
    10798 int nconsvars;
    10799 int maxnconsvars;
    10800 int nlocvars;
    10801 int nopenidx = 0;
    10802 int consnodeidx;
    10803 int nodeidx;
    10804 int i;
    10805 SCIP_Bool iscolored;
    10806 SCIP_Bool hasparentcoef;
    10807
    10808 assert(scip != NULL);
    10809 assert(cons != NULL);
    10810 assert(graph != NULL);
    10811 assert(success != NULL);
    10812
    10813 /* store lhs/rhs */
    10815 SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
    10816
    10817 rootexpr = SCIPgetExprNonlinear(cons);
    10818 assert(rootexpr != NULL);
    10819
    10820 /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
    10821 expr = SCIPgetExprNonlinear(cons);
    10822 assert(expr != NULL);
    10823
    10827
    10828 /* find potential number of nodes in graph */
    10829 maxnopenidx = 0;
    10830 for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
    10831 {
    10833 continue;
    10834
    10835 ++maxnopenidx;
    10836 }
    10837
    10838 SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
    10839
    10840 maxnconsvars = SCIPgetNVars(scip);
    10841 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
    10842 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
    10843
    10844 /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
    10845 SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
    10846
    10847 /* iterate over expression tree and store nodes/edges */
    10848 expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
    10851
    10852 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    10853 {
    10854 /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
    10855 if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
    10856 {
    10857 SCIP_EXPR* baseexpr;
    10858
    10859 baseexpr = expr;
    10860 while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
    10861 expr = SCIPexpriterGetNext(it);
    10862
    10863 SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
    10864
    10865 /* leave the expression */
    10866 continue;
    10867 }
    10868
    10869 /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
    10871 {
    10872 --nopenidx;
    10873 continue;
    10874 }
    10876
    10877 /* find parentidx */
    10878 if( expr == rootexpr )
    10879 parentidx = consnodeidx;
    10880 else
    10881 {
    10882 assert(nopenidx >= 1);
    10883 parentidx = openidx[nopenidx - 1];
    10884 }
    10885
    10886 /* possibly find a coefficient assigned to the expression by the parent */
    10887 hasparentcoef = FALSE;
    10888 if ( expr != rootexpr )
    10889 {
    10890 SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
    10891 }
    10892
    10893 /* deal with different kinds of expressions and store them in the symmetry data structure */
    10894 if( SCIPisExprVar(scip, expr) )
    10895 {
    10896 /* needed to correctly reset value when leaving expression */
    10897 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
    10898
    10899 openidx[nopenidx++] = -1;
    10900
    10901 assert(maxnconsvars > 0);
    10902 assert(parentidx > 0);
    10903
    10904 /* if the parent assigns the variable a coefficient, introduce an intermediate node */
    10905 if( hasparentcoef )
    10906 {
    10907 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
    10908
    10909 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
    10910 parentidx = nodeidx;
    10911 }
    10912
    10913 /* connect (aggregation of) variable expression with its parent */
    10914 nconsvars = 1;
    10915 consvars[0] = SCIPgetVarExprVar(expr);
    10916 consvals[0] = 1.0;
    10917 constant = 0.0;
    10918
    10919 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
    10920 &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
    10921
    10922 /* check whether variable is aggregated */
    10923 if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
    10924 {
    10925 int thisidx;
    10926
    10927 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
    10928 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
    10929
    10930 parentidx = thisidx;
    10931 }
    10932 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, parentidx, consvars, consvals,
    10933 nconsvars, constant) );
    10934 }
    10935 else if( SCIPisExprValue(scip, expr) )
    10936 {
    10937 assert(parentidx > 0);
    10938
    10939 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
    10940
    10941 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
    10942
    10943 /* needed to correctly reset value when leaving expression */
    10944 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
    10945
    10946 openidx[nopenidx++] = -1;
    10947 }
    10948 else
    10949 {
    10950 SCIP_Bool usedefaultgadget = TRUE;
    10951
    10952 assert(expr == rootexpr || parentidx > 0);
    10953 assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
    10954
    10955 if( SCIPisExprSum(scip, expr) )
    10956 {
    10957 /* deal with sum expressions differently, because we can possibly aggregate linear sums */
    10958 SCIP_EXPR** children;
    10959 int sumidx;
    10960 int optype;
    10961 int childidx;
    10962
    10963 /* sums are handled by a special gadget */
    10964 usedefaultgadget = FALSE;
    10965
    10966 /* extract all children being variables and compute the sum of active variables expression */
    10967 nlocvars = 0;
    10968 children = SCIPexprGetChildren(expr);
    10969
    10970 SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
    10971
    10972 for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
    10973 {
    10974 if( !SCIPisExprVar(scip, children[childidx]) )
    10975 continue;
    10976
    10977 consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
    10978 consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
    10979
    10980 /* store that we have already handled this expression */
    10981 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
    10982 }
    10983
    10984 constant = SCIPgetConstantExprSum(expr);
    10985
    10986 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
    10987 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
    10988
    10990
    10991 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
    10992 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
    10993
    10994 /* add the linear part of the sum */
    10995 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
    10996
    10997 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
    10998
    10999 /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
    11000 if( symtype == SYM_SYMTYPE_SIGNPERM )
    11001 {
    11002 SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
    11003 &consvars, &consvals, &maxnconsvars, handledexprs) );
    11004 }
    11005
    11006 /* store sumidx for children that have not been treated */
    11007 openidx[nopenidx++] = sumidx;
    11008 }
    11009 else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
    11010 {
    11011 SCIP_Bool succ;
    11012
    11013 SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
    11014 parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
    11015
    11016 if( succ )
    11017 {
    11018 usedefaultgadget = FALSE;
    11019 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
    11020 }
    11021 }
    11022 else if( symtype == SYM_SYMTYPE_SIGNPERM )
    11023 {
    11024 SCIP_Bool succ;
    11025
    11026 /* we can find more signed permutations for even univariate operators */
    11027 SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
    11028 &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
    11029
    11030 if( succ )
    11031 {
    11032 usedefaultgadget = FALSE;
    11033 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
    11034 }
    11035 }
    11036
    11037 if( usedefaultgadget )
    11038 {
    11039 int opidx;
    11040 int optype;
    11041
    11043 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
    11044 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
    11045
    11046 /* possibly add constants of expression */
    11048 {
    11049 SYM_EXPRDATA* symdata;
    11050
    11051 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
    11052 assert(symdata != NULL);
    11053
    11054 /* if expression has multiple constants, assign colors to edges to distinguish them */
    11055 iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
    11056 for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
    11057 {
    11058 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
    11059 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
    11060 }
    11061
    11062 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
    11063 }
    11064
    11065 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
    11066
    11067 openidx[nopenidx++] = opidx;
    11068 }
    11069 }
    11070 }
    11071
    11072 SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
    11073 SCIPfreeBufferArray(scip, &consvals);
    11074 SCIPfreeBufferArray(scip, &consvars);
    11075 SCIPfreeBufferArray(scip, &openidx);
    11076 SCIPfreeExpriter(&it);
    11077
    11078 *success = TRUE;
    11079
    11080 return SCIP_OKAY;
    11081}
    11082
    11083/*
    11084 * Callback methods of constraint handler
    11085 */
    11086
    11087/** copy method for constraint handler plugins (called when SCIP copies plugins) */
    11088static
    11089SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
    11090{ /*lint --e{715}*/
    11091 SCIP_CONSHDLR* targetconshdlr;
    11092 SCIP_CONSHDLRDATA* sourceconshdlrdata;
    11093 int i;
    11094
    11095 assert(scip != NULL);
    11096 assert(conshdlr != NULL);
    11097 assert(valid != NULL);
    11098
    11100
    11101 /* create basic data of constraint handler and include it to scip */
    11103
    11104 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    11105 assert(targetconshdlr != NULL);
    11106 assert(targetconshdlr != conshdlr);
    11107
    11108 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
    11109 assert(sourceconshdlrdata != NULL);
    11110
    11111 /* copy nonlinear handlers */
    11112 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
    11113 {
    11114 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
    11115 }
    11116
    11117 *valid = TRUE;
    11118
    11119 return SCIP_OKAY;
    11120}
    11121
    11122/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
    11123static
    11124SCIP_DECL_CONSFREE(consFreeNonlinear)
    11125{ /*lint --e{715}*/
    11126 SCIP_CONSHDLRDATA* conshdlrdata;
    11127 int i;
    11128
    11129 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11130 assert(conshdlrdata != NULL);
    11131
    11132 /* free nonlinear handlers */
    11133 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11134 {
    11135 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
    11136 assert(conshdlrdata->nlhdlrs[i] == NULL);
    11137 }
    11138 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
    11139 conshdlrdata->nlhdlrssize = 0;
    11140
    11141 /* free upgrade functions */
    11142 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
    11143 {
    11144 assert(conshdlrdata->consupgrades[i] != NULL);
    11145 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
    11146 }
    11147 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
    11148
    11149 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
    11150
    11151 SCIPqueueFree(&conshdlrdata->reversepropqueue);
    11152
    11153 if( conshdlrdata->vp_randnumgen != NULL )
    11154 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
    11155
    11156 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
    11157 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
    11158 {
    11159 if( conshdlrdata->vp_lp[i] != NULL )
    11160 {
    11161 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
    11162 }
    11163 }
    11164
    11165 assert(conshdlrdata->branchrandnumgen == NULL);
    11166
    11167 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
    11168 SCIPhashmapFree(&conshdlrdata->var2expr);
    11169
    11170 SCIPfreeBlockMemory(scip, &conshdlrdata);
    11171 SCIPconshdlrSetData(conshdlr, NULL);
    11172
    11173 return SCIP_OKAY;
    11174}
    11175
    11176
    11177/** initialization method of constraint handler (called after problem was transformed) */
    11178static
    11179SCIP_DECL_CONSINIT(consInitNonlinear)
    11180{ /*lint --e{715}*/
    11181 SCIP_CONSHDLRDATA* conshdlrdata;
    11182 int i;
    11183
    11184 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11185 assert(conshdlrdata != NULL);
    11186
    11187 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
    11188 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
    11189 /* set to 1 so it is larger than initial value of lastenforound in exprs */
    11190 conshdlrdata->enforound = 1;
    11191 /* reset numbering for auxiliary variables */
    11192 conshdlrdata->auxvarid = 0;
    11193
    11194 for( i = 0; i < nconss; ++i )
    11195 {
    11196 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
    11197 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
    11198 }
    11199
    11200 /* sort nonlinear handlers by detection priority, in decreasing order */
    11201 if( conshdlrdata->nnlhdlrs > 1 )
    11202 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
    11203
    11204 /* get heuristics for later use */
    11205 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
    11206 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
    11207
    11208 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
    11209 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11210 {
    11211 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
    11212 }
    11213
    11214 /* reset statistics in constraint handler */
    11215 conshdlrdata->nweaksepa = 0;
    11216 conshdlrdata->ntightenlp = 0;
    11217 conshdlrdata->ndesperatebranch = 0;
    11218 conshdlrdata->ndesperatecutoff = 0;
    11219 conshdlrdata->ndesperatetightenlp = 0;
    11220 conshdlrdata->nforcelp = 0;
    11221 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
    11222 conshdlrdata->ncanonicalizecalls = 0;
    11223
    11224#ifdef ENFOLOGFILE
    11225 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
    11226#endif
    11227
    11228 return SCIP_OKAY;
    11229}
    11230
    11231
    11232/** deinitialization method of constraint handler (called before transformed problem is freed) */
    11233static
    11234SCIP_DECL_CONSEXIT(consExitNonlinear)
    11235{ /*lint --e{715}*/
    11236 SCIP_CONSHDLRDATA* conshdlrdata;
    11237 SCIP_CONS** consssorted;
    11238 int i;
    11239
    11240 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11241 assert(conshdlrdata != NULL);
    11242
    11243 if( nconss > 0 )
    11244 {
    11245 /* for better performance of dropVarEvents, we sort by index, descending */
    11246 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
    11247 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
    11248
    11249 for( i = 0; i < nconss; ++i )
    11250 {
    11251 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
    11252 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
    11253 }
    11254
    11255 SCIPfreeBufferArray(scip, &consssorted);
    11256 }
    11257
    11258 conshdlrdata->subnlpheur = NULL;
    11259 conshdlrdata->trysolheur = NULL;
    11260
    11261 if( conshdlrdata->vp_randnumgen != NULL )
    11262 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
    11263
    11264 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
    11265 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
    11266 {
    11267 if( conshdlrdata->vp_lp[i] != NULL )
    11268 {
    11269 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
    11270 }
    11271 }
    11272
    11273 if( conshdlrdata->branchrandnumgen != NULL )
    11274 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
    11275
    11276 /* deinitialize nonlinear handlers */
    11277 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11278 {
    11279 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
    11280 }
    11281
    11282 ENFOLOG(
    11283 if( enfologfile != NULL )
    11284 {
    11285 fclose(enfologfile);
    11286 enfologfile = NULL;
    11287 })
    11288
    11289 return SCIP_OKAY;
    11290}
    11291
    11292
    11293/** presolving initialization method of constraint handler (called when presolving is about to begin) */
    11294#ifdef SCIP_DISABLED_CODE
    11295static
    11297{ /*lint --e{715}*/
    11298 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    11299 SCIPABORT(); /*lint --e{527}*/
    11300
    11301 return SCIP_OKAY;
    11302}
    11303#else
    11304#define consInitpreNonlinear NULL
    11305#endif
    11306
    11307
    11308/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
    11309static
    11310SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
    11311{ /*lint --e{715}*/
    11312 SCIP_Bool infeasible;
    11313
    11314 if( nconss == 0 )
    11315 return SCIP_OKAY;
    11316
    11317 /* skip some extra work if already known to be infeasible */
    11319 return SCIP_OKAY;
    11320
    11321 /* simplify constraints and replace common subexpressions */
    11322 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
    11323
    11324 /* currently SCIP does not offer to communicate this,
    11325 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
    11326 * or if a constraint expression became constant
    11327 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
    11328 */
    11329 /* assert(!infeasible); */
    11330
    11331 /* tell SCIP that we have something nonlinear */
    11333
    11334 return SCIP_OKAY;
    11335}
    11336
    11337
    11338/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
    11339static
    11340SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
    11341{ /*lint --e{715}*/
    11342 SCIP_CONSHDLRDATA* conshdlrdata;
    11343 int i;
    11344
    11345 /* skip remaining initializations if we have solved already
    11346 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
    11347 * assumes nonempty activities in expressions
    11348 */
    11349 switch( SCIPgetStatus(scip) )
    11350 {
    11355 return SCIP_OKAY;
    11356 default: ;
    11357 } /*lint !e788 */
    11358
    11359 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11360 assert(conshdlrdata != NULL);
    11361
    11362 /* reset one of the number of detections counter to count only current round */
    11363 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11364 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
    11365
    11366 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
    11367
    11368 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
    11369 if( conshdlrdata->branchpscostweight > 0.0 )
    11370 {
    11371 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
    11372 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
    11373 {
    11374 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
    11375 SCIPABORT();
    11376 return SCIP_INVALIDDATA;
    11377 }
    11378 }
    11379
    11380 return SCIP_OKAY;
    11381}
    11382
    11383
    11384/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    11385static
    11386SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
    11387{ /*lint --e{715}*/
    11388 SCIP_CONSHDLRDATA* conshdlrdata;
    11389
    11390 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
    11391
    11392 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11393 assert(conshdlrdata != NULL);
    11394
    11395 /* free hash table for bilinear terms */
    11396 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
    11397
    11398 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
    11399 conshdlrdata->checkedvarlocks = FALSE;
    11400
    11401 /* drop catching new solution event, if catched before */
    11402 if( conshdlrdata->newsoleventfilterpos >= 0 )
    11403 {
    11404 SCIP_EVENTHDLR* eventhdlr;
    11405
    11406 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
    11407 assert(eventhdlr != NULL);
    11408
    11409 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
    11410 conshdlrdata->newsoleventfilterpos = -1;
    11411 }
    11412
    11413 return SCIP_OKAY;
    11414}
    11415
    11416
    11417/** frees specific constraint data */
    11418static
    11419SCIP_DECL_CONSDELETE(consDeleteNonlinear)
    11420{ /*lint --e{715}*/
    11421 assert(consdata != NULL);
    11422 assert(*consdata != NULL);
    11423 assert((*consdata)->expr != NULL);
    11424
    11425 /* constraint locks should have been removed */
    11426 assert((*consdata)->nlockspos == 0);
    11427 assert((*consdata)->nlocksneg == 0);
    11428
    11429 /* free variable expressions */
    11430 SCIP_CALL( freeVarExprs(scip, *consdata) );
    11431
    11432 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
    11433
    11434 /* free nonlinear row representation */
    11435 if( (*consdata)->nlrow != NULL )
    11436 {
    11437 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
    11438 }
    11439
    11440 SCIPfreeBlockMemory(scip, consdata);
    11441
    11442 return SCIP_OKAY;
    11443}
    11444
    11445
    11446/** transforms constraint data into data belonging to the transformed problem */
    11447static
    11448SCIP_DECL_CONSTRANS(consTransNonlinear)
    11449{ /*lint --e{715}*/
    11450 SCIP_EXPR* targetexpr;
    11451 SCIP_CONSDATA* sourcedata;
    11452
    11453 sourcedata = SCIPconsGetData(sourcecons);
    11454 assert(sourcedata != NULL);
    11455
    11456 /* get a copy of sourceexpr with transformed vars */
    11457 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    11458 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
    11459
    11460 /* create transformed cons (only captures targetexpr, no need to copy again) */
    11461 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
    11462 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
    11463 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
    11464 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
    11465 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
    11466 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
    11467
    11468 /* release target expr */
    11469 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
    11470
    11471 return SCIP_OKAY;
    11472}
    11473
    11474
    11475/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
    11476static
    11477SCIP_DECL_CONSINITLP(consInitlpNonlinear)
    11478{ /*lint --e{715}*/
    11479 SCIP_CONSHDLRDATA* conshdlrdata;
    11480
    11481 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
    11482 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
    11483 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
    11484 * for now, there is an assert in detectNlhdlrs to require initial if separated
    11485 */
    11486 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
    11487
    11488 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11489 assert(conshdlrdata != NULL);
    11490
    11491 /* catch new solution event */
    11492 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
    11493 {
    11494 SCIP_EVENTHDLR* eventhdlr;
    11495
    11496 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
    11497 assert(eventhdlr != NULL);
    11498
    11499 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
    11500 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
    11501 }
    11502
    11503 /* collect all bilinear terms for which an auxvar is present
    11504 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
    11505 * addition (and removal?) of constraints during solve
    11506 * this is typically the majority of constraints, but the method should be made more flexible
    11507 */
    11508 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
    11509
    11510 return SCIP_OKAY;
    11511}
    11512
    11513
    11514/** separation method of constraint handler for LP solutions */
    11515static
    11516SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
    11517{ /*lint --e{715}*/
    11518 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
    11519
    11520 return SCIP_OKAY;
    11521}
    11522
    11523
    11524/** separation method of constraint handler for arbitrary primal solutions */
    11525static
    11526SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
    11527{ /*lint --e{715}*/
    11528 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
    11529
    11530 return SCIP_OKAY;
    11531}
    11532
    11533
    11534/** constraint enforcing method of constraint handler for LP solutions */
    11535static
    11536SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
    11537{ /*lint --e{715}*/
    11538 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
    11539
    11540 return SCIP_OKAY;
    11541}
    11542
    11543
    11544/** constraint enforcing method of constraint handler for relaxation solutions */
    11545static
    11546SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
    11547{ /*lint --e{715}*/
    11548 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
    11549
    11550 return SCIP_OKAY;
    11551}
    11552
    11553
    11554/** constraint enforcing method of constraint handler for pseudo solutions */
    11555static
    11556SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
    11557{ /*lint --e{715}*/
    11558 SCIP_RESULT propresult;
    11559 SCIP_Longint soltag;
    11560 int nchgbds;
    11561 int nnotify;
    11562 int c;
    11563
    11564 soltag = SCIPgetExprNewSoltag(scip);
    11565
    11566 *result = SCIP_FEASIBLE;
    11567 for( c = 0; c < nconss; ++c )
    11568 {
    11569 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
    11570
    11571 if( isConsViolated(scip, conss[c]) )
    11572 *result = SCIP_INFEASIBLE;
    11573 }
    11574
    11575 if( *result == SCIP_FEASIBLE )
    11576 return SCIP_OKAY;
    11577
    11578 /* try to propagate
    11579 * TODO obey propinenfo parameter, but we need something to recognize cutoff
    11580 */
    11581 nchgbds = 0;
    11582 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
    11583
    11584 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
    11585 {
    11586 *result = propresult;
    11587 return SCIP_OKAY;
    11588 }
    11589
    11590 /* register all unfixed variables in all violated constraints as branching candidates */
    11591 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
    11592 if( nnotify > 0 )
    11593 {
    11594 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
    11595
    11596 return SCIP_OKAY;
    11597 }
    11598
    11599 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
    11600 *result = SCIP_SOLVELP;
    11601 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
    11602
    11603 return SCIP_OKAY;
    11604}
    11605
    11606
    11607/** feasibility check method of constraint handler for integral solutions */
    11608static
    11609SCIP_DECL_CONSCHECK(consCheckNonlinear)
    11610{ /*lint --e{715}*/
    11611 SCIP_CONSHDLRDATA* conshdlrdata;
    11612 SCIP_CONSDATA* consdata;
    11613 SCIP_Real maxviol;
    11614 SCIP_Bool maypropfeasible;
    11615 SCIP_Longint soltag;
    11616 int c;
    11617
    11618 assert(scip != NULL);
    11619 assert(conshdlr != NULL);
    11620 assert(conss != NULL || nconss == 0);
    11621 assert(result != NULL);
    11622
    11623 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11624 assert(conshdlrdata != NULL);
    11625
    11626 *result = SCIP_FEASIBLE;
    11627 soltag = SCIPgetExprNewSoltag(scip);
    11628 maxviol = 0.0;
    11629 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
    11631
    11632 if( maypropfeasible && (sol == NULL || SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_LPSOL) && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
    11633 maypropfeasible = FALSE;
    11634
    11635 /* check nonlinear constraints for feasibility */
    11636 for( c = 0; c < nconss; ++c )
    11637 {
    11638 SCIP_Real absviol;
    11639 SCIP_Real relviol;
    11640
    11641 assert(conss != NULL && conss[c] != NULL);
    11642 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
    11643
    11644 absviol = getConsAbsViolation(conss[c]);
    11645 SCIP_CALL( getConsRelViolation(scip, conss[c], &relviol, sol, soltag) );
    11646 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
    11647
    11648 if( absviol > SCIPfeastol(scip) )
    11649 {
    11650 *result = SCIP_INFEASIBLE;
    11651 maxviol = MAX(maxviol, absviol);
    11652
    11653 consdata = SCIPconsGetData(conss[c]);
    11654 assert(consdata != NULL);
    11655
    11656 /* print reason for infeasibility */
    11657 if( printreason )
    11658 {
    11659 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
    11660 SCIPinfoMessage(scip, NULL, ";\n");
    11661
    11662 if( consdata->lhsviol > SCIPfeastol(scip) )
    11663 {
    11664 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
    11665 }
    11666 if( consdata->rhsviol > SCIPfeastol(scip) )
    11667 {
    11668 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
    11669 }
    11670 }
    11671 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
    11672 {
    11673 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
    11674 return SCIP_OKAY;
    11675 }
    11676
    11677 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
    11678 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
    11679 maypropfeasible = FALSE;
    11680
    11681 if( maypropfeasible )
    11682 {
    11683 if( consdata->lhsviol > SCIPfeastol(scip) )
    11684 {
    11685 /* check if there is a variable which may help to get the left hand side satisfied
    11686 * if there is no such variable, then we cannot get feasible
    11687 */
    11688 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
    11689 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
    11690 maypropfeasible = FALSE;
    11691 }
    11692 else
    11693 {
    11694 assert(consdata->rhsviol > SCIPfeastol(scip));
    11695 /* check if there is a variable which may help to get the right hand side satisfied
    11696 * if there is no such variable, then we cannot get feasible
    11697 */
    11698 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
    11699 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
    11700 maypropfeasible = FALSE;
    11701 }
    11702 }
    11703 }
    11704 }
    11705
    11706 if( *result == SCIP_INFEASIBLE && maypropfeasible )
    11707 {
    11708 SCIP_Bool success;
    11709
    11710 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
    11711
    11712 /* do not pass solution to NLP heuristic if we made it feasible this way */
    11713 if( success )
    11714 return SCIP_OKAY;
    11715 }
    11716
    11717 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
    11718 {
    11719 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
    11720 }
    11721
    11722 return SCIP_OKAY;
    11723}
    11724
    11725
    11726/** domain propagation method of constraint handler */
    11727static
    11728SCIP_DECL_CONSPROP(consPropNonlinear)
    11729{ /*lint --e{715}*/
    11730 int nchgbds = 0;
    11731
    11732 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
    11733 assert(nchgbds >= 0);
    11734
    11735 /* TODO would it make sense to check for redundant constraints? */
    11736
    11737 return SCIP_OKAY;
    11738}
    11739
    11740
    11741/** presolving method of constraint handler */
    11742static
    11743SCIP_DECL_CONSPRESOL(consPresolNonlinear)
    11744{ /*lint --e{715}*/
    11745 SCIP_CONSHDLRDATA* conshdlrdata;
    11746 SCIP_Bool infeasible;
    11747 int c;
    11748
    11749 *result = SCIP_DIDNOTFIND;
    11750
    11751 if( nconss == 0 )
    11752 {
    11753 *result = SCIP_DIDNOTRUN;
    11754 return SCIP_OKAY;
    11755 }
    11756
    11757 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11758 assert(conshdlrdata != NULL);
    11759
    11760 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
    11761 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
    11762 if( infeasible )
    11763 {
    11764 *result = SCIP_CUTOFF;
    11765 return SCIP_OKAY;
    11766 }
    11767
    11768 /* merge constraints with the same root expression */
    11769 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
    11770 {
    11771 SCIP_Bool success;
    11772
    11773 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
    11774 if( success )
    11775 *result = SCIP_SUCCESS;
    11776 }
    11777
    11778 /* propagate constraints */
    11779 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
    11780 if( *result == SCIP_CUTOFF )
    11781 return SCIP_OKAY;
    11782
    11783 /* propagate function domains (TODO integrate with simplify?) */
    11784 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
    11785 {
    11786 SCIP_RESULT localresult;
    11787 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
    11788 if( localresult == SCIP_CUTOFF )
    11789 {
    11790 *result = SCIP_CUTOFF;
    11791 return SCIP_OKAY;
    11792 }
    11793 if( localresult == SCIP_REDUCEDDOM )
    11794 *result = SCIP_REDUCEDDOM;
    11795 }
    11796
    11797 /* check for redundant constraints, remove constraints that are a value expression */
    11798 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
    11799 if( infeasible )
    11800 {
    11801 *result = SCIP_CUTOFF;
    11802 return SCIP_OKAY;
    11803 }
    11804
    11805 /* try to upgrade constraints */
    11806 for( c = 0; c < nconss; ++c )
    11807 {
    11808 SCIP_Bool upgraded;
    11809
    11810 /* skip inactive and deleted constraints */
    11811 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
    11812 continue;
    11813
    11814 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
    11815 }
    11816
    11817 /* try to change continuous variables that appear linearly to be implicit integer */
    11818 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
    11819 {
    11820 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
    11821
    11822 if( infeasible )
    11823 {
    11824 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
    11825 *result = SCIP_CUTOFF;
    11826 return SCIP_OKAY;
    11827 }
    11828 }
    11829
    11830 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
    11832 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
    11833 {
    11834 /* run this presolving technique only once because we don't want to generate identical bound disjunction
    11835 * constraints multiple times
    11836 */
    11837 conshdlrdata->checkedvarlocks = TRUE;
    11838
    11839 for( c = 0; c < nconss; ++c )
    11840 {
    11841 int tmpnchgvartypes = 0;
    11842 int tmpnaddconss = 0;
    11843
    11844 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
    11845 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
    11846 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
    11847
    11848 if( infeasible )
    11849 {
    11850 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
    11851 *result = SCIP_CUTOFF;
    11852 return SCIP_OKAY;
    11853 }
    11854
    11855 (*nchgvartypes) += tmpnchgvartypes;
    11856 (*naddconss) += tmpnaddconss;
    11857 }
    11858 }
    11859
    11860 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
    11861 *result = SCIP_SUCCESS;
    11862 else
    11863 *result = SCIP_DIDNOTFIND;
    11864
    11865 return SCIP_OKAY;
    11866}
    11867
    11868
    11869/** propagation conflict resolving method of constraint handler */
    11870#ifdef SCIP_DISABLED_CODE
    11871static
    11873{ /*lint --e{715}*/
    11874 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    11875 SCIPABORT(); /*lint --e{527}*/
    11876
    11877 return SCIP_OKAY;
    11878}
    11879#else
    11880#define consRespropNonlinear NULL
    11881#endif
    11882
    11883
    11884/** variable rounding lock method of constraint handler */
    11885static
    11886SCIP_DECL_CONSLOCK(consLockNonlinear)
    11887{ /*lint --e{715}*/
    11888 SCIP_CONSDATA* consdata;
    11889 SCIP_EXPR_OWNERDATA* ownerdata;
    11890 SCIP_Bool reinitsolve = FALSE;
    11891
    11892 assert(conshdlr != NULL);
    11893 assert(cons != NULL);
    11894
    11895 consdata = SCIPconsGetData(cons);
    11896 assert(consdata != NULL);
    11897 assert(consdata->expr != NULL);
    11898
    11899 ownerdata = SCIPexprGetOwnerData(consdata->expr);
    11900
    11901 /* check whether we need to initSolve again because
    11902 * - we have enfo initialized (nenfos >= 0)
    11903 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
    11904 */
    11905 if( ownerdata->nenfos >= 0 )
    11906 {
    11907 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
    11908 reinitsolve = TRUE;
    11909 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
    11910 reinitsolve = TRUE;
    11911 }
    11912
    11913 if( reinitsolve )
    11914 {
    11915 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
    11916 }
    11917
    11918 /* add locks */
    11919 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
    11920
    11921 if( reinitsolve )
    11922 {
    11923 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
    11924 }
    11925
    11926 return SCIP_OKAY;
    11927}
    11928
    11929
    11930/** constraint activation notification method of constraint handler */
    11931static
    11932SCIP_DECL_CONSACTIVE(consActiveNonlinear)
    11933{ /*lint --e{715}*/
    11934 SCIP_CONSDATA* consdata;
    11935 SCIP_Bool infeasible = FALSE;
    11936
    11937 consdata = SCIPconsGetData(cons);
    11938 assert(consdata != NULL);
    11939
    11940 /* simplify root expression if the constraint has been added after presolving */
    11942 {
    11943 SCIP_Bool replacedroot;
    11944
    11945 if( !consdata->issimplified )
    11946 {
    11947 SCIP_EXPR* simplified;
    11948 SCIP_Bool changed;
    11949
    11950 /* simplify constraint */
    11951 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
    11952 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    11953 assert(simplified != NULL);
    11954 consdata->expr = simplified;
    11955 consdata->issimplified = TRUE;
    11956 }
    11957
    11958 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
    11959 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
    11960 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
    11961
    11962 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
    11963 {
    11964 SCIP_CONSHDLRDATA* conshdlrdata;
    11965 SCIP_EXPRITER* it;
    11966 SCIP_EXPR* expr;
    11967
    11968 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11969 assert(conshdlrdata != NULL);
    11970
    11972 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
    11974 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    11975 {
    11976 SCIP_EXPR* child;
    11977 SCIP_EXPR* hashmapexpr;
    11978
    11979 child = SCIPexpriterGetChildExprDFS(it);
    11980 if( !SCIPisExprVar(scip, child) )
    11981 continue;
    11982
    11983 /* check which expression is stored in the hashmap for the var of child */
    11984 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
    11985 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
    11986 if( hashmapexpr != NULL && hashmapexpr != child )
    11987 {
    11989 }
    11990 }
    11991 SCIPfreeExpriter(&it);
    11992 }
    11993 }
    11994
    11995 /* store variable expressions */
    11997 {
    11998 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    11999 }
    12000
    12001 /* add manually locks to constraints that are not checked for feasibility */
    12002 if( !SCIPconsIsChecked(cons) )
    12003 {
    12004 assert(consdata->nlockspos == 0);
    12005 assert(consdata->nlocksneg == 0);
    12006
    12007 SCIP_CALL( addLocks(scip, cons, 1, 0) );
    12008 }
    12009
    12010 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
    12011 {
    12012 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
    12013 }
    12014
    12015 /* TODO deal with infeasibility */
    12016 assert(!infeasible);
    12017
    12018 return SCIP_OKAY;
    12019}
    12020
    12021
    12022/** constraint deactivation notification method of constraint handler */
    12023static
    12024SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
    12025{ /*lint --e{715}*/
    12026 SCIP_CONSHDLRDATA* conshdlrdata;
    12027
    12028 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12029 assert(conshdlrdata != NULL);
    12030
    12032 {
    12033 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
    12034 }
    12035
    12037 {
    12038 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
    12040 }
    12041
    12042 /* remove locks that have been added in consActiveExpr() */
    12043 if( !SCIPconsIsChecked(cons) )
    12044 {
    12045 SCIP_CALL( addLocks(scip, cons, -1, 0) );
    12046
    12047 assert(SCIPconsGetData(cons)->nlockspos == 0);
    12048 assert(SCIPconsGetData(cons)->nlocksneg == 0);
    12049 }
    12050
    12051 return SCIP_OKAY;
    12052}
    12053
    12054
    12055/** constraint enabling notification method of constraint handler */
    12056static
    12057SCIP_DECL_CONSENABLE(consEnableNonlinear)
    12058{ /*lint --e{715}*/
    12059 SCIP_CONSHDLRDATA* conshdlrdata;
    12060
    12061 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12062 assert(conshdlrdata != NULL);
    12063
    12065 {
    12066 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
    12067 }
    12068
    12069 return SCIP_OKAY;
    12070}
    12071
    12072
    12073/** constraint disabling notification method of constraint handler */
    12074static
    12075SCIP_DECL_CONSDISABLE(consDisableNonlinear)
    12076{ /*lint --e{715}*/
    12077 SCIP_CONSHDLRDATA* conshdlrdata;
    12078
    12079 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12080 assert(conshdlrdata != NULL);
    12081
    12083 {
    12084 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
    12085 }
    12086
    12087 return SCIP_OKAY;
    12088}
    12089
    12090/** variable deletion of constraint handler */
    12091#ifdef SCIP_DISABLED_CODE
    12092static
    12094{ /*lint --e{715}*/
    12095 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    12096 SCIPABORT(); /*lint --e{527}*/
    12097
    12098 return SCIP_OKAY;
    12099}
    12100#else
    12101#define consDelvarsNonlinear NULL
    12102#endif
    12103
    12104
    12105/** constraint display method of constraint handler */
    12106static
    12107SCIP_DECL_CONSPRINT(consPrintNonlinear)
    12108{ /*lint --e{715}*/
    12109 SCIP_CONSDATA* consdata;
    12110
    12111 consdata = SCIPconsGetData(cons);
    12112 assert(consdata != NULL);
    12113 assert(consdata->expr != NULL);
    12114
    12115 /* print left hand side for ranged constraints */
    12116 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
    12117 {
    12118 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
    12119 }
    12120
    12121 /* print expression */
    12122 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
    12123
    12124 /* print right hand side */
    12125 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
    12126 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
    12127 else if( !SCIPisInfinity(scip, consdata->rhs) )
    12128 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
    12129 else if( !SCIPisInfinity(scip, -consdata->lhs) )
    12130 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
    12131 else
    12132 SCIPinfoMessage(scip, file, " [free]");
    12133
    12134 return SCIP_OKAY;
    12135}
    12136
    12137
    12138/** constraint copying method of constraint handler */
    12139static
    12140SCIP_DECL_CONSCOPY(consCopyNonlinear)
    12141{ /*lint --e{715}*/
    12142 SCIP_CONSHDLR* targetconshdlr;
    12143 SCIP_EXPR* targetexpr = NULL;
    12144 SCIP_CONSDATA* sourcedata;
    12145
    12146 assert(cons != NULL);
    12147
    12148 sourcedata = SCIPconsGetData(sourcecons);
    12149 assert(sourcedata != NULL);
    12150
    12151 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12152 assert(targetconshdlr != NULL);
    12153
    12154 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
    12155
    12156 if( targetexpr == NULL )
    12157 *valid = FALSE;
    12158
    12159 *cons = NULL;
    12160 if( *valid )
    12161 {
    12162 /* create copy (only capture targetexpr, no need to copy again) */
    12163 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
    12164 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
    12165 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12166 }
    12167
    12168 if( targetexpr != NULL )
    12169 {
    12170 /* release target expr */
    12171 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
    12172 }
    12173
    12174 return SCIP_OKAY;
    12175}
    12176
    12177
    12178/** constraint parsing method of constraint handler */
    12179static
    12180SCIP_DECL_CONSPARSE(consParseNonlinear)
    12181{ /*lint --e{715}*/
    12182 SCIP_Real lhs;
    12183 SCIP_Real rhs;
    12184 char* endptr;
    12185 SCIP_EXPR* consexprtree;
    12186
    12187 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
    12188
    12189 assert(scip != NULL);
    12190 assert(success != NULL);
    12191 assert(str != NULL);
    12192 assert(name != NULL);
    12193 assert(cons != NULL);
    12194
    12195 *success = FALSE;
    12196
    12197 /* return if string empty */
    12198 if( !*str )
    12199 return SCIP_OKAY;
    12200
    12201 endptr = (char*)str;
    12202
    12203 /* set left and right hand side to their default values */
    12204 lhs = -SCIPinfinity(scip);
    12205 rhs = SCIPinfinity(scip);
    12206
    12207 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
    12208
    12209 /* check for left hand side */
    12210 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
    12211 {
    12212 /* there is a number coming, maybe it is a left-hand-side */
    12213 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
    12214 {
    12215 SCIPerrorMessage("error parsing number from <%s>\n", str);
    12216 return SCIP_READERROR;
    12217 }
    12218
    12219 /* ignore whitespace */
    12220 SCIP_CALL( SCIPskipSpace(&endptr) );
    12221
    12222 if( endptr[0] != '<' || endptr[1] != '=' )
    12223 {
    12224 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
    12225 lhs = -SCIPinfinity(scip);
    12226 }
    12227 else
    12228 {
    12229 /* it was indeed a left-hand-side, so continue parsing after it */
    12230 str = endptr + 2;
    12231
    12232 /* ignore whitespace */
    12233 SCIP_CALL( SCIPskipSpace((char**)&str) );
    12234 }
    12235 }
    12236
    12237 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
    12238
    12239 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
    12240 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
    12241
    12242 /* check for left or right hand side */
    12243 SCIP_CALL( SCIPskipSpace((char**)&str) );
    12244
    12245 /* check for free constraint */
    12246 if( strncmp(str, "[free]", 6) == 0 )
    12247 {
    12248 if( !SCIPisInfinity(scip, -lhs) )
    12249 {
    12250 SCIPerrorMessage("cannot have left hand side and [free] status \n");
    12251 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12252 return SCIP_OKAY;
    12253 }
    12254 *success = TRUE;
    12255 }
    12256 else
    12257 {
    12258 switch( *str )
    12259 {
    12260 case '<':
    12261 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
    12262 break;
    12263 case '=':
    12264 if( !SCIPisInfinity(scip, -lhs) )
    12265 {
    12266 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
    12267 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12268 return SCIP_OKAY;
    12269 }
    12270 else
    12271 {
    12272 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
    12273 lhs = rhs;
    12274 }
    12275 break;
    12276 case '>':
    12277 if( !SCIPisInfinity(scip, -lhs) )
    12278 {
    12279 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
    12280 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12281 return SCIP_OKAY;
    12282 }
    12283 else
    12284 {
    12285 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
    12286 break;
    12287 }
    12288 case '\0':
    12289 *success = TRUE;
    12290 break;
    12291 default:
    12292 SCIPerrorMessage("unexpected character %c\n", *str);
    12293 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12294 return SCIP_OKAY;
    12295 }
    12296 }
    12297
    12298 /* create constraint */
    12299 SCIP_CALL( createCons(scip, conshdlr, cons, name,
    12300 consexprtree, lhs, rhs, FALSE,
    12301 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12302 assert(*cons != NULL);
    12303
    12304 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12305
    12306 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
    12307
    12308 return SCIP_OKAY;
    12309}
    12310
    12311
    12312/** constraint method of constraint handler which returns the variables (if possible) */
    12313static
    12314SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
    12315{ /*lint --e{715}*/
    12316 SCIP_CONSDATA* consdata;
    12317 int i;
    12318
    12319 consdata = SCIPconsGetData(cons);
    12320 assert(consdata != NULL);
    12321
    12322 /* store variable expressions if not done so far */
    12323 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    12324
    12325 /* check whether array is too small in order to store all variables */
    12326 if( varssize < consdata->nvarexprs )
    12327 {
    12328 *success = FALSE;
    12329 return SCIP_OKAY;
    12330 }
    12331
    12332 for( i = 0; i < consdata->nvarexprs; ++i )
    12333 {
    12334 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
    12335 assert(vars[i] != NULL);
    12336 }
    12337
    12338 *success = TRUE;
    12339
    12340 return SCIP_OKAY;
    12341}
    12342
    12343/** constraint method of constraint handler which returns the number of variables (if possible) */
    12344static
    12345SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
    12346{ /*lint --e{715}*/
    12347 SCIP_CONSDATA* consdata;
    12348
    12349 consdata = SCIPconsGetData(cons);
    12350 assert(consdata != NULL);
    12351
    12352 /* store variable expressions if not done so far */
    12353 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    12354
    12355 *nvars = consdata->nvarexprs;
    12356 *success = TRUE;
    12357
    12358 return SCIP_OKAY;
    12359}
    12360
    12361/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
    12362#ifdef SCIP_DISABLED_CODE
    12363static
    12365{ /*lint --e{715}*/
    12366 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    12367 SCIPABORT(); /*lint --e{527}*/
    12368
    12369 return SCIP_OKAY;
    12370}
    12371#else
    12372#define consGetDiveBdChgsNonlinear NULL
    12373#endif
    12374
    12375/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
    12376static
    12377SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
    12378{ /*lint --e{715}*/
    12379 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
    12380
    12381 return SCIP_OKAY;
    12382}
    12383
    12384/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
    12385static
    12386SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
    12387{ /*lint --e{715}*/
    12388 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
    12389
    12390 return SCIP_OKAY;
    12391}
    12392
    12393/** output method of cons_nonlinear statistics table to output file stream 'file' */
    12394static
    12395SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
    12396{ /*lint --e{715}*/
    12397 SCIP_CONSHDLR* conshdlr;
    12398 SCIP_CONSHDLRDATA* conshdlrdata;
    12399
    12400 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12401 assert(conshdlr != NULL);
    12402
    12403 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12404 assert(conshdlrdata != NULL);
    12405
    12406 /* print statistics for constraint handler */
    12407 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
    12408 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
    12409 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
    12410 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
    12411 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
    12412 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
    12413 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
    12414 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
    12415 SCIPinfoMessage(scip, file, "\n");
    12416 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
    12417 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
    12418 SCIPinfoMessage(scip, file, "\n");
    12419
    12420 return SCIP_OKAY;
    12421}
    12422
    12423/** collect method of cons_nonlinear statistics table to SCIP_DATATREE */
    12424static
    12425SCIP_DECL_TABLECOLLECT(tableCollectNonlinear)
    12426{
    12427 SCIP_CONSHDLR* conshdlr;
    12428 SCIP_CONSHDLRDATA* conshdlrdata;
    12429
    12430 assert(scip != NULL);
    12431 assert(table != NULL);
    12432 assert(datatree != NULL);
    12433
    12434 /* Find the constraint handler */
    12435 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12436 assert(conshdlr != NULL);
    12437
    12438 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12439 assert(conshdlrdata != NULL);
    12440
    12441 /* Insert statistics */
    12442 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nweakseparation", conshdlrdata->nweaksepa) );
    12443 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ntightenlp", conshdlrdata->ntightenlp) );
    12444 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatetightenlp", conshdlrdata->ndesperatetightenlp) );
    12445 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatebranch", conshdlrdata->ndesperatebranch) );
    12446 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatecutoff", conshdlrdata->ndesperatecutoff) );
    12447 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nforcelp", conshdlrdata->nforcelp) );
    12448 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "canonicalizationtime", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime)) );
    12449
    12450 return SCIP_OKAY;
    12451}
    12452
    12453/** output method of nlhdlr statistics table to output file stream 'file' */
    12454static
    12455SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
    12456{ /*lint --e{715}*/
    12457 SCIP_CONSHDLR* conshdlr;
    12458 SCIP_CONSHDLRDATA* conshdlrdata;
    12459
    12460 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12461 assert(conshdlr != NULL);
    12462
    12463 /* skip nlhdlr table if there never were active nonlinear constraints */
    12464 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
    12465 return SCIP_OKAY;
    12466
    12467 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12468 assert(conshdlrdata != NULL);
    12469
    12470 /* print statistics for nonlinear handlers */
    12471 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
    12472
    12473 return SCIP_OKAY;
    12474}
    12475
    12476/** collect method of nlhdlr statistics table to SCIP_DATATREE */
    12477static
    12478SCIP_DECL_TABLECOLLECT(tableCollectNlhdlr)
    12479{ /*lint --e{715}*/
    12480 SCIP_CONSHDLR* conshdlr;
    12481 SCIP_CONSHDLRDATA* conshdlrdata;
    12482
    12483 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12484 assert(conshdlr != NULL);
    12485
    12486 /* skip nlhdlr table if there never were active nonlinear constraints */
    12487 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
    12488 return SCIP_OKAY;
    12489
    12490 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12491 assert(conshdlrdata != NULL);
    12492
    12493 /* collect statistics for nonlinear handlers */
    12494 SCIP_CALL( SCIPnlhdlrCollectStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, datatree) );
    12495
    12496 return SCIP_OKAY;
    12497}
    12498
    12499/** execution method of display nlhdlrs dialog */
    12500static
    12501SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
    12502{ /*lint --e{715}*/
    12503 SCIP_CONSHDLR* conshdlr;
    12504 SCIP_CONSHDLRDATA* conshdlrdata;
    12505 int i;
    12506
    12507 /* add dialog to history of dialogs that have been executed */
    12508 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
    12509
    12510 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12511 assert(conshdlr != NULL);
    12512
    12513 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12514 assert(conshdlrdata != NULL);
    12515
    12516 /* display list of nonlinear handler */
    12517 SCIPdialogMessage(scip, NULL, "\n");
    12518 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
    12519 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
    12520 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    12521 {
    12522 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
    12523 assert(nlhdlr != NULL);
    12524
    12525 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
    12526 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
    12529 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
    12530 SCIPdialogMessage(scip, NULL, "\n");
    12531 }
    12532 SCIPdialogMessage(scip, NULL, "\n");
    12533
    12534 /* next dialog will be root dialog again */
    12535 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
    12536
    12537 return SCIP_OKAY;
    12538}
    12539
    12540/*
    12541 * constraint handler specific interface methods
    12542 */
    12543
    12544/** creates the handler for nonlinear constraints and includes it in SCIP */
    12546 SCIP* scip /**< SCIP data structure */
    12547 )
    12548{
    12549 SCIP_CONSHDLRDATA* conshdlrdata;
    12550 SCIP_DIALOG* parentdialog;
    12551
    12552 /* create nonlinear constraint handler data */
    12553 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
    12554 conshdlrdata->intevalvar = intEvalVarBoundTightening;
    12555 conshdlrdata->curboundstag = 1;
    12556 conshdlrdata->lastboundrelax = 1;
    12557 conshdlrdata->curpropboundstag = 1;
    12558 conshdlrdata->newsoleventfilterpos = -1;
    12559 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
    12560 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
    12561 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
    12562
    12563 /* include constraint handler */
    12569 conshdlrCopyNonlinear,
    12570 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
    12571 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
    12572 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
    12573 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
    12574 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
    12575 consActiveNonlinear, consDeactiveNonlinear,
    12576 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
    12577 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
    12578 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
    12579 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
    12580
    12581 /* add nonlinear constraint handler parameters */
    12582 /* TODO organize into more subcategories */
    12583 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
    12584 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
    12585 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
    12586
    12587 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
    12588 "whether to check bounds of all auxiliary variable to seed reverse propagation",
    12589 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
    12590
    12591 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
    12592 "strategy on how to relax variable bounds during bound tightening: relax (n)ot, relax by (a)bsolute value, relax always by a(b)solute value, relax by (r)relative value",
    12593 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
    12594
    12595 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
    12596 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
    12597 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
    12598
    12599 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
    12600 "by how much to relax constraint sides during bound tightening",
    12601 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
    12602
    12603 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
    12604 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
    12605 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
    12606
    12607 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
    12608 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
    12609 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    12610
    12611 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
    12612 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
    12613 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
    12614
    12615 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
    12616 "maximal number of auxiliary expressions per bilinear term",
    12617 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
    12618
    12619 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
    12620 "whether to reformulate products of binary variables during presolving",
    12621 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
    12622
    12623 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
    12624 "whether to use the AND constraint handler for reformulating binary products",
    12625 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
    12626
    12627 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
    12628 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
    12629 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
    12630
    12631 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
    12632 "whether to forbid multiaggregation of nonlinear variables",
    12633 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
    12634
    12635 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
    12636 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
    12637 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
    12638
    12639 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
    12640 "whether to (re)run propagation in enforcement",
    12641 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
    12642
    12643 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
    12644 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
    12645 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
    12646
    12647 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
    12648 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
    12649 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
    12650
    12651 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
    12652 "consider efficacy requirement when deciding whether a cut is \"strong\"",
    12653 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
    12654
    12655 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
    12656 "whether to force \"strong\" cuts in enforcement",
    12657 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
    12658
    12659 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
    12660 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
    12661 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
    12662
    12663 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
    12664 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
    12665 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
    12666
    12667 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
    12668 "whether to make rows to be non-removable in the node where they are added (can prevent some cycling): 'o'ff, in 'e'nforcement only, 'a'lways",
    12669 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
    12670
    12671 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
    12672 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
    12673 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
    12674
    12675 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
    12676 "whether variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction)",
    12677 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
    12678
    12679 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
    12680 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
    12681 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
    12682
    12683 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
    12684 "whether to use external branching candidates and branching rules for branching",
    12685 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
    12686
    12687 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
    12688 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
    12689 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
    12690
    12691 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
    12692 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
    12693 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
    12694
    12695 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
    12696 "weight by how much to consider the violation assigned to a variable for its branching score",
    12697 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12698
    12699 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
    12700 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
    12701 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12702
    12703 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
    12704 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
    12705 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12706
    12707 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
    12708 "weight by how much to consider the pseudo cost of a variable for its branching score",
    12709 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12710
    12711 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
    12712 "weight by how much to consider the domain width in branching score",
    12713 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12714
    12715 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
    12716 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
    12717 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12718
    12719 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
    12720 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
    12721 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
    12722
    12723 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
    12724 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
    12725 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
    12726
    12727 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
    12728 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
    12729 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12730
    12731 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
    12732 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
    12733 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
    12734
    12735 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
    12736 "whether tight linearizations of nonlinear constraints should be added to cutpool when some heuristics finds a new solution ('o'ff, on new 'i'ncumbents, on 'e'very solution)",
    12737 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
    12738
    12739 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
    12740 "whether to assume that any constraint in the presolved problem is convex",
    12741 &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
    12742
    12743 /* include handler for bound change events */
    12744 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
    12745 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
    12746 assert(conshdlrdata->eventhdlr != NULL);
    12747
    12748 /* include tables for statistics */
    12751 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear, tableCollectNonlinear,
    12753
    12756 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr, tableCollectNlhdlr,
    12758
    12759 /* create, include, and release display nlhdlrs dialog */
    12760 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
    12761 {
    12762 SCIP_DIALOG* dialog;
    12763
    12764 assert(parentdialog != NULL);
    12765 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
    12766
    12768 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
    12770 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
    12771 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
    12772 }
    12773
    12774 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
    12775 processNewSolutionEvent, NULL) );
    12776
    12777 return SCIP_OKAY;
    12778}
    12779
    12780/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
    12782 SCIP* scip, /**< SCIP data structure */
    12783 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
    12784 int priority, /**< priority of upgrading method */
    12785 SCIP_Bool active, /**< should the upgrading method by active by default? */
    12786 const char* conshdlrname /**< name of the constraint handler */
    12787 )
    12788{
    12789 SCIP_CONSHDLR* conshdlr;
    12790 SCIP_CONSHDLRDATA* conshdlrdata;
    12791 CONSUPGRADE* consupgrade;
    12793 char paramdesc[SCIP_MAXSTRLEN];
    12794 int i;
    12795
    12796 assert(conshdlrname != NULL );
    12797 assert(nlconsupgd != NULL);
    12798
    12799 /* find the nonlinear constraint handler */
    12800 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12801 if( conshdlr == NULL )
    12802 {
    12803 SCIPerrorMessage("nonlinear constraint handler not found\n");
    12804 return SCIP_PLUGINNOTFOUND;
    12805 }
    12806
    12807 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12808 assert(conshdlrdata != NULL);
    12809
    12810 /* check whether upgrade method exists already */
    12811 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
    12812 {
    12813 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
    12814 {
    12815#ifdef SCIP_DEBUG
    12816 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
    12817#endif
    12818 return SCIP_OKAY;
    12819 }
    12820 }
    12821
    12822 /* create a nonlinear constraint upgrade data object */
    12823 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
    12824 consupgrade->consupgd = nlconsupgd;
    12825 consupgrade->priority = priority;
    12826 consupgrade->active = active;
    12827
    12828 /* insert nonlinear constraint upgrade method into constraint handler data */
    12829 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
    12830 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
    12831
    12832 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
    12833 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
    12834 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
    12835 conshdlrdata->consupgrades[i] = consupgrade;
    12836 conshdlrdata->nconsupgrades++;
    12837
    12838 /* adds parameter to turn on and off the upgrading step */
    12839 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
    12840 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
    12842 paramname, paramdesc,
    12843 &consupgrade->active, FALSE, active, NULL, NULL) );
    12844
    12845 return SCIP_OKAY;
    12846}
    12847
    12848/** creates and captures a nonlinear constraint
    12849 *
    12850 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12851 */
    12853 SCIP* scip, /**< SCIP data structure */
    12854 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12855 const char* name, /**< name of constraint */
    12856 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
    12857 SCIP_Real lhs, /**< left hand side of constraint */
    12858 SCIP_Real rhs, /**< right hand side of constraint */
    12859 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    12860 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    12861 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    12862 * Usually set to TRUE. */
    12863 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    12864 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12865 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    12866 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12867 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    12868 * Usually set to TRUE. */
    12869 SCIP_Bool local, /**< is constraint only valid locally?
    12870 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    12871 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    12872 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    12873 * adds coefficients to this constraint. */
    12874 SCIP_Bool dynamic, /**< is constraint subject to aging?
    12875 * Usually set to FALSE. Set to TRUE for own cuts which
    12876 * are separated as constraints. */
    12877 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
    12878 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    12879 )
    12880{
    12881 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
    12882 SCIP_CONSHDLR* conshdlr;
    12883
    12884 /* find the nonlinear constraint handler */
    12885 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12886 if( conshdlr == NULL )
    12887 {
    12888 SCIPerrorMessage("nonlinear constraint handler not found\n");
    12889 return SCIP_PLUGINNOTFOUND;
    12890 }
    12891
    12892 /* create constraint */
    12893 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
    12894 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12895
    12896 return SCIP_OKAY;
    12897}
    12898
    12899/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
    12900 *
    12901 * All flags can be set via SCIPconsSetFLAGNAME-methods.
    12902 *
    12903 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
    12904 *
    12905 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12906 */
    12908 SCIP* scip, /**< SCIP data structure */
    12909 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12910 const char* name, /**< name of constraint */
    12911 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
    12912 SCIP_Real lhs, /**< left hand side of constraint */
    12913 SCIP_Real rhs /**< right hand side of constraint */
    12914 )
    12915{
    12916 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
    12918
    12919 return SCIP_OKAY;
    12920}
    12921
    12922/** creates and captures a quadratic nonlinear constraint
    12923 *
    12924 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12925 */
    12927 SCIP* scip, /**< SCIP data structure */
    12928 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12929 const char* name, /**< name of constraint */
    12930 int nlinvars, /**< number of linear terms */
    12931 SCIP_VAR** linvars, /**< array with variables in linear part */
    12932 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
    12933 int nquadterms, /**< number of quadratic terms */
    12934 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
    12935 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
    12936 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
    12937 SCIP_Real lhs, /**< left hand side of quadratic equation */
    12938 SCIP_Real rhs, /**< right hand side of quadratic equation */
    12939 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    12940 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    12941 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    12942 * Usually set to TRUE. */
    12943 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    12944 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12945 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    12946 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12947 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    12948 * Usually set to TRUE. */
    12949 SCIP_Bool local, /**< is constraint only valid locally?
    12950 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    12951 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    12952 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    12953 * adds coefficients to this constraint. */
    12954 SCIP_Bool dynamic, /**< is constraint subject to aging?
    12955 * Usually set to FALSE. Set to TRUE for own cuts which
    12956 * are separated as constraints. */
    12957 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
    12958 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    12959 )
    12960{
    12961 SCIP_CONSHDLR* conshdlr;
    12962 SCIP_EXPR* expr;
    12963 int i;
    12964
    12965 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
    12966 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
    12967
    12968 /* check data for infinity or nan values */
    12969 for( i = 0; i < nlinvars; ++i )
    12970 {
    12971 if( !SCIPisFinite(lincoefs[i]) || SCIPisInfinity(scip, lincoefs[i]) )
    12972 {
    12973 SCIPerrorMessage("Infinite or nan coefficient of variable %s in quadratic constraint %s\n", SCIPvarGetName(linvars[i]), name);
    12974 return SCIP_INVALIDDATA;
    12975 }
    12976 }
    12977 for( i = 0; i < nquadterms; ++i )
    12978 {
    12979 if( !SCIPisFinite(quadcoefs[i]) || SCIPisInfinity(scip, quadcoefs[i]) )
    12980 {
    12981 SCIPerrorMessage("Infinite or nan coefficient of term %s*%s in quadratic constraint %s\n", SCIPvarGetName(quadvars1[i]), SCIPvarGetName(quadvars2[i]), name);
    12982 return SCIP_INVALIDDATA;
    12983 }
    12984 }
    12985 /* lhs and rhs will be checked in createCons */
    12986
    12987 /* get nonlinear constraint handler */
    12988 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12989 if( conshdlr == NULL )
    12990 {
    12991 SCIPerrorMessage("nonlinear constraint handler not found\n");
    12992 return SCIP_PLUGINNOTFOUND;
    12993 }
    12994
    12995 /* create quadratic expression */
    12996 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
    12997 assert(expr != NULL);
    12998
    12999 /* create nonlinear constraint */
    13000 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
    13001 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    13002
    13003 /* release quadratic expression (captured by constraint now) */
    13004 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
    13005
    13006 return SCIP_OKAY;
    13007}
    13008
    13009/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
    13010 *
    13011 * All flags can be set via SCIPconsSetFLAGNAME-methods.
    13012 *
    13013 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
    13014 *
    13015 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13016 */
    13018 SCIP* scip, /**< SCIP data structure */
    13019 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13020 const char* name, /**< name of constraint */
    13021 int nlinvars, /**< number of linear terms */
    13022 SCIP_VAR** linvars, /**< array with variables in linear part */
    13023 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
    13024 int nquadterms, /**< number of quadratic terms */
    13025 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
    13026 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
    13027 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
    13028 SCIP_Real lhs, /**< left hand side of quadratic equation */
    13029 SCIP_Real rhs /**< right hand side of quadratic equation */
    13030 )
    13031{
    13032 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
    13034
    13035 return SCIP_OKAY;
    13036}
    13037
    13038/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
    13039 *
    13040 * \f$\sqrt{\gamma + \sum_{i=1}^{n} (\alpha_i\, (x_i + \beta_i))^2} \leq \alpha_{n+1}\, (x_{n+1}+\beta_{n+1})\f$
    13041 *
    13042 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13043 */
    13045 SCIP* scip, /**< SCIP data structure */
    13046 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13047 const char* name, /**< name of constraint */
    13048 int nvars, /**< number of variables on left hand side of constraint (n) */
    13049 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
    13050 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
    13051 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
    13052 SCIP_Real constant, /**< constant on left hand side (gamma) */
    13053 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
    13054 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
    13055 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
    13056 )
    13057{
    13058 SCIP_EXPR* expr;
    13059 SCIP_EXPR* lhssum;
    13060 SCIP_EXPR* terms[2];
    13061 SCIP_Real termcoefs[2];
    13062 int i;
    13063
    13064 assert(vars != NULL || nvars == 0);
    13065
    13066 /* check values for infinity or nan */
    13067 for( i = 0; i < nvars; ++i )
    13068 {
    13069 if( coefs != NULL && ( !SCIPisFinite(coefs[i]) || SCIPisInfinity(scip, coefs[i]) ) )
    13070 {
    13071 SCIPerrorMessage("Second-order cone term with infinite or nan coefficient of variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
    13072 return SCIP_INVALIDDATA;
    13073 }
    13074 if( offsets != NULL && (!SCIPisFinite(offsets[i]) || SCIPisInfinity(scip, offsets[i])) )
    13075 {
    13076 SCIPerrorMessage("Second-order cone term with infinite or nan offset for variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
    13077 return SCIP_INVALIDDATA;
    13078 }
    13079 }
    13080 if( !SCIPisFinite(constant) || SCIPisInfinity(scip, constant) )
    13081 {
    13082 SCIPerrorMessage("Second-order cone constant with infinite or nan value in nonlinear constraint %s\n", name);
    13083 return SCIP_INVALIDDATA;
    13084 }
    13085 if( !SCIPisFinite(rhscoeff) || SCIPisInfinity(scip, rhscoeff) )
    13086 {
    13087 SCIPerrorMessage("Infinite or nan coefficient of right hand side variable in second-order cone constraint %s\n", name);
    13088 return SCIP_INVALIDDATA;
    13089 }
    13090 if( !SCIPisFinite(rhsoffset) || SCIPisInfinity(scip, rhsoffset) )
    13091 {
    13092 SCIPerrorMessage("Infinite or nan right hand side offset in second-order cone constraint %s\n", name);
    13093 return SCIP_INVALIDDATA;
    13094 }
    13095 /* lhs and rhs will be checked in createCons */
    13096
    13097 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
    13098 for( i = 0; i < nvars; ++i )
    13099 {
    13100 SCIP_EXPR* varexpr;
    13101 SCIP_EXPR* powexpr;
    13102
    13103 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
    13104 if( offsets != NULL && offsets[i] != 0.0 )
    13105 {
    13106 SCIP_EXPR* sum;
    13107 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
    13108 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
    13109 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
    13110 }
    13111 else
    13112 {
    13113 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
    13114 }
    13115
    13116 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
    13117 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
    13118 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
    13119 }
    13120
    13121 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
    13122 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
    13123 termcoefs[0] = 1.0;
    13124
    13125 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
    13126 termcoefs[1] = -rhscoeff;
    13127
    13128 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
    13129
    13130 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
    13131 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
    13132
    13133 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
    13134
    13135 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
    13136
    13137 return SCIP_OKAY;
    13138}
    13139
    13140/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
    13141 *
    13142 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
    13143 *
    13144 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13145 */
    13147 SCIP* scip, /**< SCIP data structure */
    13148 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13149 const char* name, /**< name of constraint */
    13150 SCIP_VAR* x, /**< nonlinear variable x in constraint */
    13151 SCIP_VAR* z, /**< linear variable z in constraint */
    13152 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
    13153 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
    13154 SCIP_Real zcoef, /**< coefficient of z in constraint */
    13155 SCIP_Real lhs, /**< left hand side of constraint */
    13156 SCIP_Real rhs /**< right hand side of constraint */
    13157 )
    13158{
    13159 SCIP_EXPR* xexpr;
    13160 SCIP_EXPR* terms[2];
    13161 SCIP_Real coefs[2];
    13162 SCIP_EXPR* sumexpr;
    13163
    13164 assert(x != NULL);
    13165 assert(z != NULL);
    13166
    13167 if( !SCIPisFinite(exponent) )
    13168 {
    13169 SCIPerrorMessage("exponent in nonlinear signpower constraint <%s> is infinite or nan\n", name);
    13170 return SCIP_INVALIDDATA;
    13171 }
    13172
    13173 if( !SCIPisFinite(xoffset) )
    13174 {
    13175 SCIPerrorMessage("argument offset in nonlinear signpower constraint <%s> is infinite or nan\n", name);
    13176 return SCIP_INVALIDDATA;
    13177 }
    13178
    13179 if( !SCIPisFinite(zcoef) )
    13180 {
    13181 SCIPerrorMessage("coefficient of linear variable in nonlinear signpower constraint <%s> is infinite or nan\n", name);
    13182 return SCIP_INVALIDDATA;
    13183 }
    13184
    13185 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
    13186 if( xoffset != 0.0 )
    13187 {
    13188 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
    13189 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
    13190
    13191 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
    13192 }
    13193 else
    13194 {
    13195 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
    13196 }
    13197 coefs[0] = 1.0;
    13198
    13199 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
    13200 coefs[1] = zcoef;
    13201
    13202 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
    13203
    13204 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
    13205
    13206 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
    13207 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
    13208 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
    13209 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
    13210
    13211 return SCIP_OKAY;
    13212}
    13213
    13214/** gets tag indicating current local variable bounds */
    13216 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13217 )
    13218{
    13219 SCIP_CONSHDLRDATA* conshdlrdata;
    13220
    13221 assert(conshdlr != NULL);
    13222 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13223
    13224 return conshdlrdata->curboundstag;
    13225}
    13226
    13227/** gets the `curboundstag` from the last time where variable bounds were relaxed */
    13229 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13230 )
    13231{
    13232 SCIP_CONSHDLRDATA* conshdlrdata;
    13233
    13234 assert(conshdlr != NULL);
    13235 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13236
    13237 return conshdlrdata->lastboundrelax;
    13238}
    13239
    13240/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
    13241 *
    13242 * @attention This method is not intended for normal use.
    13243 * These tags are maintained by the event handler for variable bound change events.
    13244 * This method is used by some unittests.
    13245 */
    13247 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13248 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
    13249 )
    13250{
    13251 SCIP_CONSHDLRDATA* conshdlrdata;
    13252
    13253 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13254 assert(conshdlrdata != NULL);
    13255
    13256 ++conshdlrdata->curboundstag;
    13257 assert(conshdlrdata->curboundstag > 0);
    13258
    13259 if( boundrelax )
    13260 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
    13261}
    13262
    13263/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
    13265 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13266 )
    13267{
    13268 assert(conshdlr != NULL);
    13269
    13270 return SCIPconshdlrGetData(conshdlr)->var2expr;
    13271}
    13272
    13273/** processes a rowprep for cut addition and maybe report branchscores */
    13275 SCIP* scip, /**< SCIP data structure */
    13276 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
    13277 SCIP_CONS* cons, /**< nonlinear constraint */
    13278 SCIP_EXPR* expr, /**< expression */
    13279 SCIP_ROWPREP* rowprep, /**< cut to be added */
    13280 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
    13281 SCIP_VAR* auxvar, /**< auxiliary variable */
    13282 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
    13283 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
    13284 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
    13285 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
    13286 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
    13287 SCIP_RESULT* result /**< pointer to store the result */
    13288 )
    13289{
    13290 SCIP_Real cutviol;
    13291 SCIP_CONSHDLRDATA* conshdlrdata;
    13292 SCIP_Real auxvarvalue = SCIP_INVALID;
    13293 SCIP_Bool sepasuccess;
    13294 SCIP_Real estimateval = SCIP_INVALID;
    13295 SCIP_Real mincutviolation;
    13296
    13297 assert(nlhdlr != NULL);
    13298 assert(cons != NULL);
    13299 assert(expr != NULL);
    13300 assert(rowprep != NULL);
    13301 assert(auxvar != NULL);
    13302 assert(result != NULL);
    13303
    13304 /* decide on minimal violation of cut */
    13305 if( sol == NULL )
    13306 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
    13307 else
    13308 mincutviolation = SCIPfeastol(scip);
    13309
    13310 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    13311 assert(conshdlrdata != NULL);
    13312
    13313 sepasuccess = TRUE;
    13314
    13315 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
    13316 if( cutviol > 0.0 )
    13317 {
    13318 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
    13319
    13320 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
    13321 if( !allowweakcuts && auxvalue != SCIP_INVALID )
    13322 {
    13323 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
    13324 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
    13325 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
    13326 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
    13327 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
    13328 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
    13329 *
    13330 * if we are overestimating, we have z >= c'x-b >= f(x)
    13331 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
    13332 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
    13333 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
    13334 *
    13335 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
    13336 */
    13337 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
    13338 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
    13339 {
    13340 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
    13341 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
    13342 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
    13343 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
    13344 sepasuccess = FALSE;
    13345 }
    13346 }
    13347
    13348 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
    13349 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
    13350 }
    13351 else
    13352 {
    13353 sepasuccess = FALSE;
    13354 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
    13355 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
    13356 }
    13357
    13358 /* clean up estimator */
    13359 if( sepasuccess )
    13360 {
    13361 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
    13362 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
    13363 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
    13364 SCIPprintRowprep(scip, rowprep, enfologfile); )
    13365
    13366 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
    13367 * instead, may even scale them down, that is, scale so that max coef is close to 1
    13368 */
    13369 if( !allowweakcuts )
    13370 {
    13371 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
    13372
    13373 if( !sepasuccess )
    13374 {
    13375 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
    13376 }
    13377 else
    13378 {
    13379 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
    13380 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
    13381 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
    13382 if( sepasuccess )
    13383 sepasuccess = cutviol > mincutviolation;
    13384 }
    13385
    13386 if( sepasuccess && auxvalue != SCIP_INVALID )
    13387 {
    13388 /* check whether cut is weak now
    13389 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
    13390 * reconstructing estimateval from cutviol (TODO improve or remove?)
    13391 */
    13392 SCIP_Real auxvarcoef = 0.0;
    13393 int i;
    13394
    13395 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
    13396 * it should be...
    13397 */
    13398 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
    13399 {
    13400 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
    13401 {
    13402 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
    13403 break;
    13404 }
    13405 }
    13406
    13407 if( auxvarcoef == 0.0 ||
    13408 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
    13409 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
    13410 {
    13411 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
    13412 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
    13413 sepasuccess = FALSE;
    13414 }
    13415 }
    13416 }
    13417 else
    13418 {
    13419 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
    13420
    13421 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
    13422 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
    13423 */
    13424 if( !branchscoresuccess )
    13426
    13427 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
    13428
    13429 if( !sepasuccess )
    13430 {
    13431 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
    13432 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
    13433 }
    13434
    13435 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
    13436 * changed
    13437 */
    13438 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
    13439 {
    13440 SCIP_Real violscore;
    13441
    13442#ifdef BRSCORE_ABSVIOL
    13443 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
    13444#else
    13445 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
    13446#endif
    13447 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
    13448
    13449 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
    13450 * - were fixed,
    13451 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
    13452 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
    13453 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
    13454 * so I'm disabling the assert for now
    13455 */
    13456 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
    13457 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
    13458 }
    13459 }
    13460 }
    13461
    13462 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
    13463 if( sepasuccess )
    13464 {
    13465 SCIP_ROW* row;
    13466
    13467 if( conshdlrdata->branchdualweight > 0.0 )
    13468 {
    13469 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
    13470 * skip if gap is zero
    13471 */
    13472 if( auxvalue == SCIP_INVALID )
    13473 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
    13474 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
    13475 {
    13476 char gap[40];
    13477 /* coverity[secure_coding] */
    13478 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
    13479 strcat(SCIProwprepGetName(rowprep), gap);
    13480 }
    13481 }
    13482
    13483 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
    13484
    13485 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
    13486 {
    13487 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
    13489 }
    13490 else if( !SCIPisCutApplicable(scip, row) )
    13491 {
    13492 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
    13493 }
    13494 else
    13495 {
    13496 SCIP_Bool infeasible;
    13497
    13498 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
    13499 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
    13500
    13501 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
    13502 * if we haven't found strong cuts before)
    13503 */
    13504 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
    13505
    13506 /* mark row as not removable from LP for current node (this can prevent some cycling) */
    13507 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
    13509
    13510 if( infeasible )
    13511 {
    13512 *result = SCIP_CUTOFF;
    13514 }
    13515 else
    13516 {
    13517 *result = SCIP_SEPARATED;
    13519 }
    13520 }
    13521
    13522 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    13523 }
    13524 else if( branchscoresuccess )
    13525 {
    13526 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
    13527 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
    13528
    13529 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
    13530 * expressions eligible for branching candidate, see enforceConstraints() and branching()
    13531 */
    13532 *result = SCIP_BRANCHED;
    13533 }
    13534 else
    13535 {
    13536 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
    13537 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
    13538 " (!)" : ""); )
    13539 }
    13540
    13541 return SCIP_OKAY;
    13542}
    13543
    13544/** returns whether all nonlinear constraints are assumed to be convex */
    13546 SCIP_CONSHDLR* conshdlr
    13547 )
    13548{
    13549 SCIP_CONSHDLRDATA* conshdlrdata;
    13550
    13551 assert(conshdlr != NULL);
    13552
    13553 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13554 assert(conshdlrdata != NULL);
    13555
    13556 return conshdlrdata->assumeconvex;
    13557}
    13558
    13559/** collects all bilinear terms for a given set of constraints
    13560 *
    13561 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
    13562 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
    13563 */
    13565 SCIP* scip, /**< SCIP data structure */
    13566 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13567 SCIP_CONS** conss, /**< nonlinear constraints */
    13568 int nconss /**< total number of nonlinear constraints */
    13569 )
    13570{
    13571 assert(conshdlr != NULL);
    13572 assert(conss != NULL || nconss == 0);
    13573
    13574 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
    13575
    13576 return SCIP_OKAY;
    13577}
    13578
    13579/** returns the total number of bilinear terms that are contained in all nonlinear constraints
    13580 *
    13581 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13582 */
    13584 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13585 )
    13586{
    13587 SCIP_CONSHDLRDATA* conshdlrdata;
    13588
    13589 assert(conshdlr != NULL);
    13590
    13591 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13592 assert(conshdlrdata != NULL);
    13593
    13594 return conshdlrdata->nbilinterms;
    13595}
    13596
    13597/** returns all bilinear terms that are contained in all nonlinear constraints
    13598 *
    13599 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13600 * @note The value of the auxiliary variable of a bilinear term might be NULL, which indicates that the term does not have an auxiliary variable.
    13601 */
    13603 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13604 )
    13605{
    13606 SCIP_CONSHDLRDATA* conshdlrdata;
    13607
    13608 assert(conshdlr != NULL);
    13609
    13610 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13611 assert(conshdlrdata != NULL);
    13612
    13613 return conshdlrdata->bilinterms;
    13614}
    13615
    13616/** returns the index of the bilinear term representing the product of the two given variables
    13617 *
    13618 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13619 * @return The method returns -1 if the variables do not appear bilinearly.
    13620 */
    13622 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13623 SCIP_VAR* x, /**< first variable */
    13624 SCIP_VAR* y /**< second variable */
    13625 )
    13626{
    13627 SCIP_CONSHDLRDATA* conshdlrdata;
    13629 int idx;
    13630
    13631 assert(conshdlr != NULL);
    13632 assert(x != NULL);
    13633 assert(y != NULL);
    13634
    13635 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13636 assert(conshdlrdata != NULL);
    13637
    13638 if( conshdlrdata->bilinhashtable == NULL )
    13639 {
    13640 return -1;
    13641 }
    13642
    13643 /* ensure that x.index <= y.index */
    13644 if( SCIPvarCompare(x, y) == 1 )
    13645 {
    13646 SCIPswapPointers((void**)&x, (void**)&y);
    13647 }
    13648 assert(SCIPvarCompare(x, y) < 1);
    13649
    13650 /* use a new entry to find the image in the bilinear hash table */
    13651 entry.x = x;
    13652 entry.y = y;
    13653 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
    13654 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
    13655 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
    13656 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
    13657
    13658 return idx;
    13659}
    13660
    13661/** returns the bilinear term that represents the product of two given variables
    13662 *
    13663 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13664 * @return The method returns NULL if the variables do not appear bilinearly.
    13665 */
    13667 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13668 SCIP_VAR* x, /**< first variable */
    13669 SCIP_VAR* y /**< second variable */
    13670 )
    13671{
    13672 SCIP_CONSHDLRDATA* conshdlrdata;
    13673 int idx;
    13674
    13675 assert(conshdlr != NULL);
    13676 assert(x != NULL);
    13677 assert(y != NULL);
    13678
    13679 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13680 assert(conshdlrdata != NULL);
    13681
    13682 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
    13683 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
    13684
    13685 if( idx >= 0 )
    13686 {
    13687 return &conshdlrdata->bilinterms[idx];
    13688 }
    13689
    13690 return NULL;
    13691}
    13692
    13693/** evaluates an auxiliary expression for a bilinear term */
    13695 SCIP* scip, /**< SCIP data structure */
    13696 SCIP_VAR* x, /**< first variable of the bilinear term */
    13697 SCIP_VAR* y, /**< second variable of the bilinear term */
    13698 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
    13699 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
    13700 )
    13701{
    13702 assert(scip != NULL);
    13703 assert(x != NULL);
    13704 assert(y != NULL);
    13705 assert(auxexpr != NULL);
    13706 assert(auxexpr->auxvar != NULL);
    13707
    13708 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
    13709 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
    13710}
    13711
    13712/** stores the variables of a bilinear term in the data of the constraint handler */
    13714 SCIP* scip, /**< SCIP data structure */
    13715 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    13716 SCIP_VAR* x, /**< first variable */
    13717 SCIP_VAR* y, /**< second variable */
    13718 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
    13719 int nlockspos, /**< number of positive expression locks */
    13720 int nlocksneg /**< number of negative expression locks */
    13721 )
    13722{
    13723 SCIP_CONSHDLRDATA* conshdlrdata;
    13725 int idx;
    13726
    13727 assert(conshdlr != NULL);
    13728
    13729 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13730 assert(conshdlrdata != NULL);
    13731
    13732 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
    13733
    13734 term = &conshdlrdata->bilinterms[idx];
    13735 assert(term != NULL);
    13736 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
    13737 assert(term->aux.var == NULL); /* there should not already be an auxvar, that is, existing terms should exist only once (common subexprs should have been eliminated) */
    13738
    13739 /* store and capture auxiliary variable */
    13740 if( auxvar != NULL )
    13741 {
    13742 term->aux.var = auxvar;
    13743 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
    13744 }
    13745
    13746 return SCIP_OKAY;
    13747}
    13748
    13749/** stores the variables of a bilinear term in the data of the constraint handler */
    13751 SCIP* scip, /**< SCIP data structure */
    13752 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    13753 SCIP_VAR* x, /**< first variable */
    13754 SCIP_VAR* y, /**< second variable */
    13755 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
    13756 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
    13757 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
    13758 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
    13759 SCIP_Real cst, /**< constant of the auxiliary expression */
    13760 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
    13761 )
    13762{
    13763 SCIP_CONSHDLRDATA* conshdlrdata;
    13766 int idx;
    13767 int nlockspos;
    13768 int nlocksneg;
    13769 SCIP_Bool added;
    13770
    13771 assert(conshdlr != NULL);
    13772
    13773 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13774 assert(conshdlrdata != NULL);
    13775
    13776 nlockspos = overestimate ? 1 : 0;
    13777 nlocksneg = overestimate ? 0 : 1;
    13778
    13779 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
    13780
    13781 term = &conshdlrdata->bilinterms[idx];
    13782 assert(term != NULL);
    13783 assert(SCIPvarCompare(term->x, term->y) < 1);
    13784
    13785 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
    13786 {
    13787 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
    13788 /* this is the case where we are adding an implicitly defined relation for a product that has already
    13789 * been explicitly defined; convert auxvar into an auxexpr */
    13790
    13791 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
    13792 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
    13793 return SCIP_OKAY;
    13794
    13795 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
    13796 auxvarexpr->cst = 0.0;
    13797 auxvarexpr->coefs[0] = 1.0;
    13798 auxvarexpr->coefs[1] = 0.0;
    13799 auxvarexpr->coefs[2] = 0.0;
    13800 auxvarexpr->auxvar = term->aux.var;
    13801 auxvarexpr->underestimate = term->nlocksneg > 0;
    13802 auxvarexpr->overestimate = term->nlockspos > 0;
    13803
    13804 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
    13805 term->aux.exprs = NULL;
    13806
    13807 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
    13808
    13809 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
    13810 assert(added);
    13811 }
    13812
    13813 /* create and add auxexpr */
    13814 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
    13815 auxexpr->underestimate = !overestimate;
    13816 auxexpr->overestimate = overestimate;
    13817 auxexpr->auxvar = auxvar;
    13818 auxexpr->coefs[0] = coefaux;
    13819 if( term->x == x )
    13820 {
    13821 assert(term->y == y);
    13822 auxexpr->coefs[1] = coefx;
    13823 auxexpr->coefs[2] = coefy;
    13824 }
    13825 else
    13826 {
    13827 assert(term->x == y);
    13828 assert(term->y == x);
    13829 auxexpr->coefs[1] = coefy;
    13830 auxexpr->coefs[2] = coefx;
    13831 }
    13832 auxexpr->cst = cst;
    13833 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
    13834
    13835 if( !added )
    13836 {
    13837 SCIPfreeBlockMemory(scip, &auxexpr);
    13838 }
    13839 else if( auxvar != NULL )
    13840 { /* capture auxiliary variable */
    13841 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
    13842 }
    13843
    13844 return SCIP_OKAY;
    13845}
    13846
    13847/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
    13849 SCIP* scip, /**< SCIP data structure */
    13850 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13851 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
    13852 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
    13853 void* fundata, /**< data for function evaluation (can be NULL) */
    13854 SCIP_Real* xstar, /**< point to be separated */
    13855 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
    13856 int nallvars, /**< half of the length of box */
    13857 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
    13858 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
    13859 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
    13860 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
    13861 )
    13862{
    13863 SCIP_Real* corner;
    13864 SCIP_Real* funvals;
    13865 int* nonfixedpos;
    13866 SCIP_Real maxfaceterror;
    13867 int nvars; /* number of nonfixed variables */
    13868 unsigned int ncorners;
    13869 unsigned int i;
    13870 int j;
    13871
    13872 assert(scip != NULL);
    13873 assert(conshdlr != NULL);
    13874 assert(function != NULL);
    13875 assert(xstar != NULL);
    13876 assert(box != NULL);
    13877 assert(success != NULL);
    13878 assert(facetcoefs != NULL);
    13879 assert(facetconstant != NULL);
    13880
    13881 *success = FALSE;
    13882
    13883 /* identify fixed variables */
    13884 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
    13885 nvars = 0;
    13886 for( j = 0; j < nallvars; ++j )
    13887 {
    13888 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
    13889 continue;
    13890 nonfixedpos[nvars] = j;
    13891 nvars++;
    13892 }
    13893
    13894 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
    13895 * if too many variables are not fixed, then we do nothing currently
    13896 */
    13897 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
    13898 {
    13899 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
    13900 SCIPfreeBufferArray(scip, &nonfixedpos);
    13901 return SCIP_OKAY;
    13902 }
    13903
    13904 /* compute f(v^i) for each corner v^i of [l,u] */
    13905 ncorners = POWEROFTWO(nvars);
    13906 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
    13907 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
    13908 for( j = 0; j < nallvars; ++j )
    13909 {
    13910 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
    13911 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
    13912 }
    13913 for( i = 0; i < ncorners; ++i )
    13914 {
    13915 SCIPdebugMsg(scip, "corner %u: ", i);
    13916 for( j = 0; j < nvars; ++j )
    13917 {
    13918 int varpos = nonfixedpos[j];
    13919 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
    13920 * we check this by shifting i for j positions to the right and checking whether the last bit is set
    13921 */
    13922 if( (i >> j) & 0x1 )
    13923 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
    13924 else
    13925 corner[varpos] = box[2 * varpos ]; /* lb of var */
    13926 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
    13927 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
    13928 }
    13929
    13930 funvals[i] = function(corner, nallvars, fundata);
    13931
    13932 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
    13933
    13934 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
    13935 {
    13936 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
    13937 goto CLEANUP;
    13938 }
    13939 }
    13940
    13941 /* clear coefs array; below we only fill in coefs for nonfixed variables */
    13942 BMSclearMemoryArray(facetcoefs, nallvars);
    13943
    13944 if( nvars == 1 )
    13945 {
    13946 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
    13947
    13948 /* check whether target has been missed */
    13949 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
    13950 {
    13951 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
    13952 *success = FALSE;
    13953 }
    13954 }
    13955 else if( nvars == 2 && SCIPlapackIsAvailable() )
    13956 {
    13957 int idx1 = nonfixedpos[0];
    13958 int idx2 = nonfixedpos[1];
    13959 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
    13960 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
    13961 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
    13962 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
    13963 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
    13964 SCIP_Real coefs[2] = { 0.0, 0.0 };
    13965
    13966 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
    13967
    13968 facetcoefs[idx1] = coefs[0];
    13969 facetcoefs[idx2] = coefs[1];
    13970 }
    13971 else
    13972 {
    13973 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
    13974 }
    13975 if( !*success )
    13976 {
    13977 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
    13978 goto CLEANUP;
    13979 }
    13980
    13981 /*
    13982 * check and adjust facet with the algorithm of Rikun et al.
    13983 */
    13984
    13985 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
    13986
    13987 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
    13988 if( maxfaceterror > 0.0 )
    13989 {
    13990 SCIP_CONSHDLRDATA* conshdlrdata;
    13991 SCIP_Real midval;
    13992 SCIP_Real feastol;
    13993
    13995
    13996 /* evaluate function in middle point to get some idea for a scaling */
    13997 for( j = 0; j < nvars; ++j )
    13998 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
    13999 midval = function(corner, nallvars, fundata);
    14000 if( midval == SCIP_INVALID )
    14001 midval = 1.0;
    14002
    14003 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    14004 assert(conshdlrdata != NULL);
    14005
    14006 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
    14007 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
    14008 {
    14009 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
    14010 *success = FALSE;
    14011 goto CLEANUP;
    14012 }
    14013
    14014 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
    14015
    14016 if( overestimate )
    14017 *facetconstant += maxfaceterror;
    14018 else
    14019 *facetconstant -= maxfaceterror;
    14020 }
    14021
    14022 /* if we made it until here, then we have a nice facet */
    14023 assert(*success);
    14024
    14025CLEANUP:
    14026 /* free allocated memory */
    14027 SCIPfreeBufferArray(scip, &corner);
    14028 SCIPfreeBufferArray(scip, &funvals);
    14029 SCIPfreeBufferArray(scip, &nonfixedpos);
    14030
    14031 return SCIP_OKAY;
    14032}
    14033
    14034/*
    14035 * constraint specific interface methods
    14036 */
    14037
    14038/** returns the expression of the given nonlinear constraint */
    14040 SCIP_CONS* cons /**< constraint data */
    14041 )
    14042{
    14043 SCIP_CONSDATA* consdata;
    14044
    14045 assert(cons != NULL);
    14046
    14048
    14049 consdata = SCIPconsGetData(cons);
    14050 assert(consdata != NULL);
    14051
    14052 return consdata->expr;
    14053}
    14054
    14055/** gets the left hand side of a nonlinear constraint */
    14057 SCIP_CONS* cons /**< constraint data */
    14058 )
    14059{
    14060 SCIP_CONSDATA* consdata;
    14061
    14062 assert(cons != NULL);
    14063
    14065
    14066 consdata = SCIPconsGetData(cons);
    14067 assert(consdata != NULL);
    14068
    14069 return consdata->lhs;
    14070}
    14071
    14072/** gets the right hand side of a nonlinear constraint */
    14074 SCIP_CONS* cons /**< constraint data */
    14075 )
    14076{
    14077 SCIP_CONSDATA* consdata;
    14078
    14079 assert(cons != NULL);
    14080
    14082
    14083 consdata = SCIPconsGetData(cons);
    14084 assert(consdata != NULL);
    14085
    14086 return consdata->rhs;
    14087}
    14088
    14089/** gets the nonlinear constraint as a nonlinear row representation. */
    14091 SCIP* scip, /**< SCIP data structure */
    14092 SCIP_CONS* cons, /**< constraint */
    14093 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
    14094 )
    14095{
    14096 SCIP_CONSDATA* consdata;
    14097
    14098 assert(cons != NULL);
    14099 assert(nlrow != NULL);
    14100
    14102
    14103 consdata = SCIPconsGetData(cons);
    14104 assert(consdata != NULL);
    14105
    14106 if( consdata->nlrow == NULL )
    14107 {
    14108 SCIP_CALL( createNlRow(scip, cons) );
    14109 }
    14110 assert(consdata->nlrow != NULL);
    14111 *nlrow = consdata->nlrow;
    14112
    14113 return SCIP_OKAY;
    14114}
    14115
    14116/** returns the curvature of the expression of a given nonlinear constraint
    14117 *
    14118 * @note The curvature information is computed during CONSINITSOL.
    14119 */
    14121 SCIP_CONS* cons /**< constraint data */
    14122 )
    14123{
    14124 SCIP_CONSDATA* consdata;
    14125
    14126 assert(cons != NULL);
    14127
    14129
    14130 consdata = SCIPconsGetData(cons);
    14131 assert(consdata != NULL);
    14132
    14133 return consdata->curv;
    14134}
    14135
    14136/** checks whether expression of constraint can be represented as quadratic form
    14137 *
    14138 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
    14139 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
    14140 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
    14141 */
    14143 SCIP* scip, /**< SCIP data structure */
    14144 SCIP_CONS* cons, /**< constraint data */
    14145 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
    14146 )
    14147{
    14148 SCIP_CONSDATA* consdata;
    14149
    14150 assert(scip != NULL);
    14151 assert(cons != NULL);
    14152 assert(isquadratic != NULL);
    14153
    14155
    14156 consdata = SCIPconsGetData(cons);
    14157 assert(consdata != NULL);
    14158 assert(consdata->expr != NULL);
    14159
    14160 /* check whether constraint expression is quadratic in extended formulation */
    14161 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
    14162
    14163 /* if not quadratic in non-extended formulation, then do indicate quadratic */
    14164 if( *isquadratic )
    14165 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
    14166
    14167 return SCIP_OKAY;
    14168}
    14169
    14170/** changes left-hand-side of a nonlinear constraint
    14171 *
    14172 * @attention This method can only be called in the problem stage.
    14173 */
    14175 SCIP* scip, /**< SCIP data structure */
    14176 SCIP_CONS* cons, /**< constraint data */
    14177 SCIP_Real lhs /**< new left-hand-side */
    14178 )
    14179{
    14180 SCIP_CONSDATA* consdata;
    14181
    14182 assert(scip != NULL);
    14183 assert(cons != NULL);
    14184
    14186
    14188 {
    14189 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
    14190 return SCIP_INVALIDCALL;
    14191 }
    14192
    14193 /* we should have an original constraint */
    14194 assert(SCIPconsIsOriginal(cons));
    14195
    14196 consdata = SCIPconsGetData(cons);
    14197 assert(consdata != NULL);
    14198
    14199 if( consdata->lhs == lhs )
    14200 return SCIP_OKAY;
    14201
    14202 consdata->lhs = lhs;
    14203
    14204 /* not sure we care about any of these flags for original constraints */
    14205 consdata->ispropagated = FALSE;
    14206
    14207 return SCIP_OKAY;
    14208}
    14209
    14210/** changes right-hand-side of a nonlinear constraint
    14211 *
    14212 * @attention This method can only be called in the problem stage.
    14213 */
    14215 SCIP* scip, /**< SCIP data structure */
    14216 SCIP_CONS* cons, /**< constraint data */
    14217 SCIP_Real rhs /**< new right-hand-side */
    14218 )
    14219{
    14220 SCIP_CONSDATA* consdata;
    14221
    14222 assert(scip != NULL);
    14223 assert(cons != NULL);
    14224
    14226
    14228 {
    14229 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
    14230 return SCIP_INVALIDCALL;
    14231 }
    14232
    14233 /* we should have an original constraint */
    14234 assert(SCIPconsIsOriginal(cons));
    14235
    14236 consdata = SCIPconsGetData(cons);
    14237 assert(consdata != NULL);
    14238
    14239 if( consdata->rhs == rhs )
    14240 return SCIP_OKAY;
    14241
    14242 consdata->rhs = rhs;
    14243
    14244 /* not sure we care about any of these flags for original constraints */
    14245 consdata->ispropagated = FALSE;
    14246
    14247 return SCIP_OKAY;
    14248}
    14249
    14250/** changes expression of a nonlinear constraint
    14251 *
    14252 * @attention This method can only be called in the problem stage.
    14253 */
    14255 SCIP* scip, /**< SCIP data structure */
    14256 SCIP_CONS* cons, /**< constraint data */
    14257 SCIP_EXPR* expr /**< new expression */
    14258 )
    14259{
    14260 SCIP_CONSHDLR* conshdlr;
    14261 SCIP_CONSDATA* consdata;
    14262
    14263 assert(scip != NULL);
    14264 assert(cons != NULL);
    14265 assert(expr != NULL);
    14266
    14268 {
    14269 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
    14270 return SCIP_INVALIDCALL;
    14271 }
    14272
    14273 /* we should have an original constraint */
    14274 assert(SCIPconsIsOriginal(cons));
    14275
    14276 conshdlr = SCIPconsGetHdlr(cons);
    14277 assert(conshdlr != NULL);
    14278
    14280
    14281 consdata = SCIPconsGetData(cons);
    14282 assert(consdata != NULL);
    14283 assert(consdata->expr != NULL);
    14284
    14285 /* we should not have collected additional data for the expr
    14286 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
    14287 */
    14288 assert(consdata->nvarexprs == 0);
    14289 assert(consdata->varexprs == NULL);
    14290 assert(!consdata->catchedevents);
    14291
    14292 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    14293
    14294 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
    14295 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    14296
    14297 /* not sure we care about any of these flags for original constraints */
    14298 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
    14299 consdata->issimplified = FALSE;
    14300 consdata->ispropagated = FALSE;
    14301
    14302 return SCIP_OKAY;
    14303}
    14304
    14305/** adds coef * var to nonlinear constraint
    14306 *
    14307 * @attention This method can only be called in the problem stage.
    14308 */
    14310 SCIP* scip, /**< SCIP data structure */
    14311 SCIP_CONS* cons, /**< constraint data */
    14312 SCIP_VAR* var, /**< variable */
    14313 SCIP_Real coef /**< coefficient */
    14314 )
    14315{
    14316 SCIP_CONSHDLR* conshdlr;
    14317 SCIP_CONSDATA* consdata;
    14318 SCIP_EXPR* varexpr;
    14319
    14320 assert(scip != NULL);
    14321 assert(cons != NULL);
    14322
    14324 {
    14325 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
    14326 return SCIP_INVALIDCALL;
    14327 }
    14328
    14329 /* we should have an original constraint */
    14330 assert(SCIPconsIsOriginal(cons));
    14331
    14332 if( coef == 0.0 )
    14333 return SCIP_OKAY;
    14334
    14335 conshdlr = SCIPconsGetHdlr(cons);
    14336 assert(conshdlr != NULL);
    14337
    14339
    14340 consdata = SCIPconsGetData(cons);
    14341 assert(consdata != NULL);
    14342 assert(consdata->expr != NULL);
    14343
    14344 /* we should not have collected additional data for it
    14345 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
    14346 */
    14347 assert(consdata->nvarexprs == 0);
    14348 assert(consdata->varexprs == NULL);
    14349 assert(!consdata->catchedevents);
    14350
    14351 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
    14352
    14353 /* append to sum, if consdata->expr is sum and not used anywhere else */
    14354 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
    14355 {
    14356 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
    14357 }
    14358 else
    14359 {
    14360 /* create new expression = 1 * consdata->expr + coef * var */
    14361 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
    14362 SCIP_Real coefs[2] = { 1.0, coef };
    14363
    14364 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
    14365
    14366 /* release old root expr */
    14367 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
    14368 }
    14369
    14370 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
    14371
    14372 /* not sure we care about any of these flags for original constraints */
    14373 consdata->issimplified = FALSE;
    14374 consdata->ispropagated = FALSE;
    14375
    14376 return SCIP_OKAY;
    14377}
    14378
    14379/** adds coef * expr to nonlinear constraint
    14380 *
    14381 * @attention This method can only be called in the problem stage.
    14382 */
    14384 SCIP* scip, /**< SCIP data structure */
    14385 SCIP_CONS* cons, /**< nonlinear constraint */
    14386 SCIP_EXPR* expr, /**< expression */
    14387 SCIP_Real coef /**< coefficient */
    14388 )
    14389{
    14390 SCIP_CONSHDLR* conshdlr;
    14391 SCIP_CONSDATA* consdata;
    14392 SCIP_EXPR* exprowned;
    14393
    14394 assert(scip != NULL);
    14395 assert(cons != NULL);
    14396
    14398 {
    14399 SCIPerrorMessage("SCIPaddExprNonlinear can only be called in problem stage.\n");
    14400 return SCIP_INVALIDCALL;
    14401 }
    14402
    14403 /* we should have an original constraint */
    14404 assert(SCIPconsIsOriginal(cons));
    14405
    14406 if( coef == 0.0 )
    14407 return SCIP_OKAY;
    14408
    14409 conshdlr = SCIPconsGetHdlr(cons);
    14410 assert(conshdlr != NULL);
    14411
    14413
    14414 consdata = SCIPconsGetData(cons);
    14415 assert(consdata != NULL);
    14416 assert(consdata->expr != NULL);
    14417
    14418 /* free quadratic representation, if any is stored */
    14419 SCIPfreeExprQuadratic(scip, consdata->expr);
    14420
    14421 /* free varexprs in consdata, in case they have been stored
    14422 * (e.g., by a call to consGet(N)VarsNonlinear)
    14423 */
    14424 SCIP_CALL( freeVarExprs(scip, consdata) );
    14425
    14426 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
    14427 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    14428
    14429 /* append to sum, if consdata->expr is sum and not used anywhere else */
    14430 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
    14431 {
    14432 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
    14433 }
    14434 else
    14435 {
    14436 /* create new expression = 1 * consdata->expr + coef * var */
    14437 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
    14438 SCIP_Real coefs[2] = { 1.0, coef };
    14439
    14440 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
    14441
    14442 /* release old root expr */
    14443 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
    14444 }
    14445
    14446 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
    14447
    14448 /* not sure we care about any of these flags for original constraints */
    14449 consdata->issimplified = FALSE;
    14450 consdata->ispropagated = FALSE;
    14451
    14452 return SCIP_OKAY;
    14453}
    14454
    14455/** computes value of constraint expression in a given solution
    14456 *
    14457 * Stores value of constraint expression in sol in activity.
    14458 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
    14459 */
    14461 SCIP* scip, /**< SCIP data structure */
    14462 SCIP_CONS* cons, /**< constraint */
    14463 SCIP_SOL* sol, /**< solution */
    14464 SCIP_Real* activity /**< buffer to store computed activity */
    14465 )
    14466{
    14467 SCIP_CONSDATA* consdata;
    14468
    14469 assert(cons != NULL);
    14470 assert(activity != NULL);
    14471
    14472 consdata = SCIPconsGetData(cons);
    14473 assert(consdata != NULL);
    14474
    14475 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
    14476 *activity = SCIPexprGetEvalValue(consdata->expr);
    14477
    14478 return SCIP_OKAY;
    14479}
    14480
    14481/** gets absolute violation of nonlinear constraint
    14482 *
    14483 * This function evaluates the constraints in the given solution.
    14484 *
    14485 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
    14486 */
    14488 SCIP* scip, /**< SCIP data structure */
    14489 SCIP_CONS* cons, /**< constraint */
    14490 SCIP_SOL* sol, /**< solution to check */
    14491 SCIP_Real* viol /**< buffer to store computed violation */
    14492 )
    14493{
    14494 assert(cons != NULL);
    14495 assert(viol != NULL);
    14496
    14497 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
    14498 *viol = getConsAbsViolation(cons);
    14499
    14500 return SCIP_OKAY;
    14501}
    14502
    14503/** gets scaled violation of nonlinear constraint
    14504 *
    14505 * This function evaluates the constraints in the given solution.
    14506 *
    14507 * The scaling that is applied to the absolute violation of the constraint
    14508 * depends on the setting of parameter constraints/nonlinear/violscale.
    14509 */
    14511 SCIP* scip, /**< SCIP data structure */
    14512 SCIP_CONS* cons, /**< constraint */
    14513 SCIP_SOL* sol, /**< solution to check */
    14514 SCIP_Real* viol /**< buffer to store computed violation */
    14515 )
    14516{
    14517 assert(cons != NULL);
    14518 assert(viol != NULL);
    14519
    14520 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
    14521 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
    14522
    14523 return SCIP_OKAY;
    14524}
    14525
    14526/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
    14528 SCIP* scip, /**< SCIP data structure */
    14529 SCIP_CONS* cons, /**< nonlinear constraint */
    14530 SCIP_VAR** var, /**< pointer to store the variable */
    14531 SCIP_Real* coef /**< pointer to store the coefficient */
    14532 )
    14533{
    14534 SCIP_CONSDATA* consdata;
    14535
    14536 assert(cons != NULL);
    14537 assert(var != NULL);
    14538 assert(coef != NULL);
    14539
    14540 /* check for a linear variable that can be increased or decreased without harming feasibility */
    14542
    14543 consdata = SCIPconsGetData(cons);
    14544 assert(consdata != NULL);
    14545
    14546 *var = consdata->linvardecr;
    14547 *coef = consdata->linvardecrcoef;
    14548}
    14549
    14550/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
    14552 SCIP* scip, /**< SCIP data structure */
    14553 SCIP_CONS* cons, /**< nonlinear constraint */
    14554 SCIP_VAR** var, /**< pointer to store the variable */
    14555 SCIP_Real* coef /**< pointer to store the coefficient */
    14556 )
    14557{
    14558 SCIP_CONSDATA* consdata;
    14559
    14560 assert(cons != NULL);
    14561 assert(var != NULL);
    14562 assert(coef != NULL);
    14563
    14564 /* check for a linear variable that can be increased or decreased without harming feasibility */
    14566
    14567 consdata = SCIPconsGetData(cons);
    14568 assert(consdata != NULL);
    14569
    14570 *var = consdata->linvarincr;
    14571 *coef = consdata->linvarincrcoef;
    14572}
    14573
    14574
    14575/*
    14576 * Methods for Expressions in Nonlinear Constraints
    14577 */
    14578
    14579/** returns the number of positive rounding locks of an expression */
    14581 SCIP_EXPR* expr /**< expression */
    14582 )
    14583{
    14584 assert(expr != NULL);
    14585 assert(SCIPexprGetOwnerData(expr) != NULL);
    14586
    14587 return SCIPexprGetOwnerData(expr)->nlockspos;
    14588}
    14589
    14590/** returns the number of negative rounding locks of an expression */
    14592 SCIP_EXPR* expr /**< expression */
    14593 )
    14594{
    14595 assert(expr != NULL);
    14596 assert(SCIPexprGetOwnerData(expr) != NULL);
    14597
    14598 return SCIPexprGetOwnerData(expr)->nlocksneg;
    14599}
    14600
    14601/** returns the variable used for linearizing a given expression (return value might be NULL)
    14602 *
    14603 * @note for variable expression it returns the corresponding variable
    14604 */
    14606 SCIP_EXPR* expr /**< expression */
    14607 )
    14608{
    14609 SCIP_EXPR_OWNERDATA* ownerdata;
    14610
    14611 assert(expr != NULL);
    14612
    14613 ownerdata = SCIPexprGetOwnerData(expr);
    14614 assert(ownerdata != NULL);
    14615
    14616 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
    14617}
    14618
    14619/** returns the number of enforcements for an expression */
    14621 SCIP_EXPR* expr /**< expression */
    14622 )
    14623{
    14624 assert(expr != NULL);
    14625 assert(SCIPexprGetOwnerData(expr) != NULL);
    14626
    14627 return SCIPexprGetOwnerData(expr)->nenfos;
    14628}
    14629
    14630/** returns the data for one of the enforcements of an expression */
    14632 SCIP_EXPR* expr, /**< expression */
    14633 int idx, /**< position of enforcement in enfos array */
    14634 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
    14635 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
    14636 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
    14637 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
    14638 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
    14639 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
    14640 )
    14641{
    14642 SCIP_EXPR_OWNERDATA* ownerdata;
    14643
    14644 assert(expr != NULL);
    14645
    14646 ownerdata = SCIPexprGetOwnerData(expr);
    14647 assert(ownerdata != NULL);
    14648 assert(idx >= 0);
    14649 assert(idx < ownerdata->nenfos);
    14650 assert(ownerdata->enfos[idx] != NULL);
    14651 assert(nlhdlr != NULL);
    14652
    14653 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
    14654
    14655 if( nlhdlrexprdata != NULL )
    14656 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
    14657
    14658 if( nlhdlrparticipation != NULL )
    14659 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
    14660
    14661 if( sepabelowusesactivity != NULL )
    14662 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
    14663
    14664 if( sepaaboveusesactivity != NULL )
    14665 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
    14666
    14667 if( auxvalue != NULL )
    14668 *auxvalue = ownerdata->enfos[idx]->auxvalue;
    14669}
    14670
    14671/** sets the auxiliary value of expression for one of the enforcements of an expression */
    14673 SCIP_EXPR* expr, /**< expression */
    14674 int idx, /**< position of enforcement in enfos array */
    14675 SCIP_Real auxvalue /**< the new value of auxval */
    14676 )
    14677{
    14678 SCIP_EXPR_OWNERDATA* ownerdata;
    14679
    14680 assert(expr != NULL);
    14681
    14682 ownerdata = SCIPexprGetOwnerData(expr);
    14683 assert(ownerdata != NULL);
    14684
    14685 assert(idx >= 0);
    14686 assert(idx < ownerdata->nenfos);
    14687 assert(ownerdata->enfos[idx] != NULL);
    14688
    14689 ownerdata->enfos[idx]->auxvalue = auxvalue;
    14690}
    14691
    14692/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
    14693 *
    14694 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
    14695 */
    14697 SCIP_EXPR* expr /**< expression */
    14698 )
    14699{
    14700 assert(expr != NULL);
    14701 assert(SCIPexprGetOwnerData(expr) != NULL);
    14702
    14703 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
    14704}
    14705
    14706/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
    14707 *
    14708 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
    14709 */
    14711 SCIP_EXPR* expr /**< expression */
    14712 )
    14713{
    14714 assert(expr != NULL);
    14715 assert(SCIPexprGetOwnerData(expr) != NULL);
    14716
    14717 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
    14718}
    14719
    14720/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
    14721 *
    14722 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
    14723 */
    14725 SCIP_EXPR* expr /**< expression */
    14726 )
    14727{
    14728 assert(expr != NULL);
    14729 assert(SCIPexprGetOwnerData(expr) != NULL);
    14730
    14731 return SCIPexprGetOwnerData(expr)->nauxvaruses;
    14732}
    14733
    14734/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
    14735 *
    14736 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
    14737 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
    14738 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
    14739 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
    14740 * and also increments this count for all variables in the expression.
    14741 *
    14742 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
    14743 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
    14744 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
    14745 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
    14746 */
    14748 SCIP* scip, /**< SCIP data structure */
    14749 SCIP_EXPR* expr, /**< expression */
    14750 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
    14751 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
    14752 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
    14753 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
    14754 )
    14755{
    14756 SCIP_EXPR_OWNERDATA* ownerdata;
    14757
    14758 assert(expr != NULL);
    14759
    14760 ownerdata = SCIPexprGetOwnerData(expr);
    14761 assert(ownerdata != NULL);
    14762
    14763 /* do not store auxvar request for variable expressions */
    14764 if( useauxvar && SCIPisExprVar(scip, expr) )
    14765 useauxvar = FALSE;
    14766
    14767 if( ownerdata->nenfos >= 0 &&
    14768 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
    14769 (ownerdata->nauxvaruses == 0 && useauxvar)
    14770 ) )
    14771 {
    14772 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
    14773 * we require additional enforcement methods, that is,
    14774 * - activity of expr was not used before but will be used now, or
    14775 * - auxiliary variable of expr was not required before but will be used now
    14776 */
    14777 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
    14778 }
    14779
    14780 if( useauxvar )
    14781 ++ownerdata->nauxvaruses;
    14782
    14783 if( useactivityforprop )
    14784 ++ownerdata->nactivityusesprop;
    14785
    14786 if( useactivityforsepabelow || useactivityforsepaabove )
    14787 ++ownerdata->nactivityusessepa;
    14788
    14789 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
    14790 * information is used in detectNlhdlr()
    14791 */
    14792 if( useactivityforsepabelow )
    14793 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
    14794 if( useactivityforsepaabove )
    14795 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
    14796
    14797 if( useactivityforprop )
    14798 {
    14799 /* if activity will be used for propagation, then make sure there is a valid activity
    14800 * this way, we can do a reversepropcall after detectNlhdlr
    14801 */
    14803 }
    14804
    14805 /* increase the nactivityusedsepa counter for all variables used in the given expression */
    14806 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
    14807 {
    14808 SCIP_EXPRITER* it;
    14809
    14810 /* create and initialize iterator */
    14813
    14814 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    14815 if( SCIPisExprVar(scip, expr) )
    14816 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
    14817
    14818 /* free iterator */
    14819 SCIPfreeExpriter(&it);
    14820 }
    14821
    14822 return SCIP_OKAY;
    14823}
    14824
    14825/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
    14826 *
    14827 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
    14828 * Assume that f(x) is associated with auxiliary variable z.
    14829 *
    14830 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
    14831 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
    14832 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
    14833 *
    14834 * If necessary, f is evaluated in the given solution. If that fails (domain error),
    14835 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
    14836 */
    14838 SCIP* scip, /**< SCIP data structure */
    14839 SCIP_EXPR* expr, /**< expression */
    14840 SCIP_SOL* sol, /**< solution */
    14841 SCIP_Longint soltag, /**< tag of solution */
    14842 SCIP_Real* viol, /**< buffer to store computed violation */
    14843 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
    14844 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
    14845 )
    14846{
    14847 assert(scip != NULL);
    14848 assert(expr != NULL);
    14849 assert(viol != NULL);
    14850
    14851 /* make sure expression has been evaluated */
    14852 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
    14853
    14854 /* get violation from internal method */
    14855 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
    14856
    14857 return SCIP_OKAY;
    14858}
    14859
    14860/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
    14861 *
    14862 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
    14863 * Assume that f(w) is associated with auxiliary variable z.
    14864 *
    14865 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
    14866 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
    14867 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
    14868 *
    14869 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
    14870 * both `violover` and `violunder` are set to TRUE.
    14871 */
    14873 SCIP* scip, /**< SCIP data structure */
    14874 SCIP_EXPR* expr, /**< expression */
    14875 SCIP_Real auxvalue, /**< the value of f(w) */
    14876 SCIP_SOL* sol, /**< solution that has been evaluated */
    14877 SCIP_Real* viol, /**< buffer to store computed violation */
    14878 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
    14879 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
    14880 )
    14881{
    14882 assert(scip != NULL);
    14883 assert(expr != NULL);
    14884 assert(viol != NULL);
    14885
    14886 /* get violation from internal method */
    14887 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
    14888
    14889 return SCIP_OKAY;
    14890}
    14891
    14892
    14893/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
    14894 *
    14895 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
    14896 * Assume that f(w) is associated with auxiliary variable z.
    14897 *
    14898 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
    14899 * the absolute violation divided by max(1,|f(w)|).
    14900 *
    14901 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
    14902 * both `violover` and `violunder` are set to TRUE.
    14903 */
    14905 SCIP* scip, /**< SCIP data structure */
    14906 SCIP_EXPR* expr, /**< expression */
    14907 SCIP_Real auxvalue, /**< the value of f(w) */
    14908 SCIP_SOL* sol, /**< solution that has been evaluated */
    14909 SCIP_Real* viol, /**< buffer to store computed violation */
    14910 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
    14911 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
    14912 )
    14913{
    14914 assert(scip != NULL);
    14915 assert(expr != NULL);
    14916 assert(viol != NULL);
    14917
    14918 /* get violation from internal method */
    14919 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
    14920
    14921 if( !SCIPisInfinity(scip, *viol) )
    14922 {
    14923 assert(auxvalue != SCIP_INVALID);
    14924 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
    14925 *viol /= MAX(1.0, REALABS(auxvalue));
    14926 }
    14927
    14928 return SCIP_OKAY;
    14929}
    14930
    14931/** returns bounds on the expression
    14932 *
    14933 * This gives an intersection of bounds from
    14934 * - activity calculation (SCIPexprGetActivity()), if valid,
    14935 * - auxiliary variable, if present,
    14936 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
    14937 *
    14938 * @note The returned interval can be empty!
    14939 */
    14941 SCIP* scip, /**< SCIP data structure */
    14942 SCIP_EXPR* expr /**< expression */
    14943 )
    14944{
    14945 SCIP_EXPR_OWNERDATA* ownerdata;
    14946 SCIP_CONSHDLRDATA* conshdlrdata;
    14947 SCIP_INTERVAL bounds;
    14948
    14949 assert(scip != NULL);
    14950 assert(expr != NULL);
    14951
    14952 ownerdata = SCIPexprGetOwnerData(expr);
    14953 assert(ownerdata != NULL);
    14954
    14955 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    14956 assert(conshdlrdata != NULL);
    14957
    14958 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
    14959
    14960 /* start with propbounds if they belong to current propagation */
    14961 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
    14962 {
    14963 bounds = ownerdata->propbounds;
    14964 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
    14965 }
    14966 else
    14968
    14969 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
    14970 {
    14971 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
    14972 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
    14974 }
    14975
    14976 if( ownerdata->auxvar != NULL )
    14977 {
    14978 /* apply auxiliary variable bounds to bounds */
    14979 SCIP_INTERVAL auxvarbounds;
    14980
    14981 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
    14982 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
    14983 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
    14984 }
    14985
    14986 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
    14987
    14988 return bounds;
    14989}
    14990
    14991/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
    14992 * corresponding (auxiliary) variable (if any)
    14993 *
    14994 * @attention this function should only be called during domain propagation in cons_nonlinear
    14995 */
    14997 SCIP* scip, /**< SCIP data structure */
    14998 SCIP_EXPR* expr, /**< expression to be tightened */
    14999 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
    15000 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
    15001 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
    15002 )
    15003{
    15004 SCIP_EXPR_OWNERDATA* ownerdata;
    15005 SCIP_CONSHDLRDATA* conshdlrdata;
    15006
    15007 assert(scip != NULL);
    15008 assert(expr != NULL);
    15009 assert(cutoff != NULL);
    15010
    15011 ownerdata = SCIPexprGetOwnerData(expr);
    15012 assert(ownerdata != NULL);
    15013 assert(ownerdata->conshdlr != NULL);
    15014
    15015 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15016 assert(conshdlrdata != NULL);
    15017
    15018 /* the code below assumes that current activity is valid
    15019 * if it turns out that we cannot ensure that, then we should change code
    15020 */
    15021 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
    15023
    15024 *cutoff = FALSE;
    15025
    15026#ifdef DEBUG_PROP
    15027 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
    15028 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    15029 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
    15030#endif
    15031
    15032 if( SCIPexprIsIntegral(expr) )
    15033 {
    15034 /* apply integrality to new bounds
    15035 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
    15036 */
    15037 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
    15038 newbounds.inf = SCIPceil(scip, newbounds.inf);
    15039 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
    15040 newbounds.sup = SCIPfloor(scip, newbounds.sup);
    15041#ifdef DEBUG_PROP
    15042 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
    15043#endif
    15044 }
    15045
    15047 {
    15048 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
    15049
    15050 *cutoff = TRUE;
    15051 return SCIP_OKAY;
    15052 }
    15053
    15054 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
    15055 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
    15056 {
    15057 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
    15058
    15059 *cutoff = TRUE;
    15060 return SCIP_OKAY;
    15061 }
    15062
    15063 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
    15064 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
    15065 {
    15066 /* if already having propbounds in expr, then tighten newbounds by propbounds */
    15067 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
    15068 }
    15069 else
    15070 {
    15071 /* first time we have propbounds for expr in this propagation rounds:
    15072 * intersect with activity (though don't let it become empty if very close intervals)
    15073 */
    15074 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
    15075 }
    15076#ifdef DEBUG_PROP
    15077 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
    15078#endif
    15079
    15080 /* check if the new bounds lead to an empty interval */
    15082 {
    15083 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
    15084
    15085 *cutoff = TRUE;
    15086 return SCIP_OKAY;
    15087 }
    15088
    15089 /* if expr is not constant or variable, then store newbounds in expr->propbounds
    15090 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
    15091 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
    15092 */
    15093 if( SCIPexprGetNChildren(expr) > 0 )
    15094 {
    15095 ownerdata->propbounds = newbounds;
    15096 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
    15097 }
    15098
    15099 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
    15100 * propagation or update of auxvar bounds
    15101 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
    15102 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
    15103 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
    15104 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
    15105 * one or should we not even update propbounds to newbounds if the update is small?
    15106 */
    15107 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
    15108 {
    15109#ifdef DEBUG_PROP
    15110 SCIPdebugMsg(scip, " new bounds [%g,%g] for expr %p not sufficiently tighter than activity -- not adding to propqueue or tightening auxvar\n", newbounds.inf, newbounds.sup, (void*)expr);
    15111#endif
    15112 return SCIP_OKAY;
    15113 }
    15114
    15115 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
    15116 {
    15117 /* add expression to propagation queue if not there yet and not var or constant and
    15118 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
    15119 */
    15120#ifdef DEBUG_PROP
    15121 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
    15122#endif
    15123 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
    15124 ownerdata->inpropqueue = TRUE;
    15125 }
    15126
    15127 /* update bounds on variable or auxiliary variable */
    15128 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
    15129
    15130 return SCIP_OKAY;
    15131}
    15132
    15133/** mark constraints that include this expression to be propagated again
    15134 *
    15135 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
    15136 * a change of variable bounds, e.g., because new information on the expression is available
    15137 * that could potentially lead to tighter expression activity values.
    15138 *
    15139 * Note, that this call marks also constraints for propagation which only share some variable
    15140 * with this expression.
    15141 */
    15143 SCIP* scip, /**< SCIP data structure */
    15144 SCIP_EXPR* expr /**< expression to propagate again */
    15145 )
    15146{
    15147 SCIP_EXPRITER* it;
    15148 SCIP_CONSDATA* consdata;
    15149 SCIP_EXPR_OWNERDATA* ownerdata;
    15150 int c;
    15151
    15152 assert(scip != NULL);
    15153 assert(expr != NULL);
    15154
    15155 ownerdata = SCIPexprGetOwnerData(expr);
    15156 assert(ownerdata != NULL);
    15157
    15158 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
    15159
    15162
    15163 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    15164 {
    15165 if( !SCIPisExprVar(scip, expr) )
    15166 continue;
    15167
    15168 ownerdata = SCIPexprGetOwnerData(expr);
    15169 assert(ownerdata != NULL);
    15170
    15171 for( c = 0; c < ownerdata->nconss; ++c )
    15172 {
    15173 consdata = SCIPconsGetData(ownerdata->conss[c]);
    15174 assert(consdata != NULL);
    15175 consdata->ispropagated = FALSE;
    15176 }
    15177 }
    15178
    15179 SCIPfreeExpriter(&it);
    15180
    15181 return SCIP_OKAY;
    15182}
    15183
    15184/** adds violation-branching score to an expression
    15185 *
    15186 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
    15187 * The expression must either be a variable expression or have an aux-variable.
    15188 * In the latter case, branching on auxiliary variables must have been enabled.
    15189 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
    15190 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
    15191 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
    15192 *
    15193 * @see SCIPaddExprsViolScoreNonlinear()
    15194 */
    15196 SCIP* scip, /**< SCIP data structure */
    15197 SCIP_EXPR* expr, /**< expression where to add branching score */
    15198 SCIP_Real violscore /**< violation score to add to expression */
    15199 )
    15200{
    15201 SCIP_EXPR_OWNERDATA* ownerdata;
    15202 SCIP_CONSHDLRDATA* conshdlrdata;
    15203
    15204 assert(scip != NULL);
    15205 assert(expr != NULL);
    15206 assert(violscore >= 0.0);
    15207
    15208 ownerdata = SCIPexprGetOwnerData(expr);
    15209 assert(ownerdata != NULL);
    15210
    15211 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15212 assert(conshdlrdata != NULL);
    15213
    15214 /* if not allowing to branch on auxvars, then expr must be a var-expr */
    15215 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
    15216 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
    15217 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
    15218
    15219 /* reset branching score if we are in a different enfo round */
    15220 if( ownerdata->violscoretag != conshdlrdata->enforound )
    15221 {
    15222 ownerdata->violscoresum = violscore;
    15223 ownerdata->violscoremax = violscore;
    15224 ownerdata->nviolscores = 1;
    15225 ownerdata->violscoretag = conshdlrdata->enforound;
    15226 return;
    15227 }
    15228
    15229 ownerdata->violscoresum += violscore;
    15230 if( violscore > ownerdata->violscoremax )
    15231 ownerdata->violscoremax = violscore;
    15232 ++ownerdata->nviolscores;
    15233}
    15234
    15235/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
    15236 *
    15237 * Each expression must either be a variable expression or have an aux-variable.
    15238 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
    15239 * variables present in `exprs`.
    15240 */
    15242 SCIP* scip, /**< SCIP data structure */
    15243 SCIP_EXPR** exprs, /**< expressions where to add branching score */
    15244 int nexprs, /**< number of expressions */
    15245 SCIP_Real violscore, /**< violation score to add to expression */
    15246 SCIP_SOL* sol, /**< current solution */
    15247 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
    15248 )
    15249{
    15250 SCIP_EXPRITER* it;
    15251 SCIP_EXPR** varexprs;
    15252 SCIP_EXPR* e;
    15253 int nvars;
    15254 int varssize;
    15255 int i;
    15256
    15257 assert(exprs != NULL || nexprs == 0);
    15258 assert(success != NULL);
    15259
    15260 if( nexprs == 0 )
    15261 {
    15262 *success = FALSE;
    15263 return SCIP_OKAY;
    15264 }
    15265
    15266 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
    15267 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
    15268 {
    15269 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
    15270 return SCIP_OKAY;
    15271 }
    15272
    15273 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
    15274 nvars = 0;
    15275 varssize = 5;
    15276 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
    15277
    15280
    15281 for( i = 0; i < nexprs; ++i )
    15282 {
    15283 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
    15284 {
    15285 assert(e != NULL);
    15286
    15287 if( SCIPisExprVar(scip, e) )
    15288 {
    15289 /* add variable expression to vars array */
    15290 if( varssize == nvars )
    15291 {
    15292 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
    15293 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
    15294 }
    15295 assert(varssize > nvars);
    15296
    15297 varexprs[nvars++] = e;
    15298 }
    15299 }
    15300 }
    15301
    15302 SCIPfreeExpriter(&it);
    15303
    15304 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
    15305
    15306 SCIPfreeBufferArray(scip, &varexprs);
    15307
    15308 return SCIP_OKAY;
    15309}
    15310
    15311/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
    15313 SCIP_EXPR* expr /**< expression */
    15314 )
    15315{
    15316 SCIP_EXPR_OWNERDATA* ownerdata;
    15317 SCIP_CONSHDLRDATA* conshdlrdata;
    15318
    15319 assert(expr != NULL);
    15320
    15321 ownerdata = SCIPexprGetOwnerData(expr);
    15322 assert(ownerdata != NULL);
    15323
    15324 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15325 assert(conshdlrdata != NULL);
    15326
    15327 if( conshdlrdata->enforound != ownerdata->violscoretag )
    15328 return 0.0;
    15329
    15330 if( ownerdata->nviolscores == 0 )
    15331 return 0.0;
    15332
    15333 switch( conshdlrdata->branchscoreagg )
    15334 {
    15335 case 'a' :
    15336 /* average */
    15337 return ownerdata->violscoresum / ownerdata->nviolscores;
    15338
    15339 case 'm' :
    15340 /* maximum */
    15341 return ownerdata->violscoremax;
    15342
    15343 case 's' :
    15344 /* sum */
    15345 return ownerdata->violscoresum;
    15346
    15347 default:
    15348 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
    15349 SCIPABORT();
    15350 return SCIP_INVALID;
    15351 }
    15352}
    15353
    15354/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
    15355 *
    15356 * @see SCIPexprGetDerivative()
    15357 */
    15359 SCIP* scip, /**< SCIP data structure */
    15360 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
    15361 SCIP_VAR* var /**< variable (needs to be in the expression) */
    15362 )
    15363{
    15364 SCIP_EXPR_OWNERDATA* ownerdata;
    15365 SCIP_CONSHDLRDATA* conshdlrdata;
    15366 SCIP_EXPR* varexpr;
    15367
    15368 assert(scip != NULL);
    15369 assert(expr != NULL);
    15370 assert(var != NULL);
    15371
    15372 /* return 0.0 for value expression */
    15373 if( SCIPisExprValue(scip, expr) )
    15374 {
    15375 assert(SCIPexprGetDerivative(expr) == 0.0);
    15376 return 0.0;
    15377 }
    15378
    15379 /* check if an error occurred during the last SCIPevalExprGradient() call */
    15380 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
    15381 return SCIP_INVALID;
    15382
    15383 ownerdata = SCIPexprGetOwnerData(expr);
    15384 assert(ownerdata != NULL);
    15385
    15386 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15387 assert(conshdlrdata != NULL);
    15388
    15389 /* use variable to expressions mapping which is stored in the constraint handler data */
    15390 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
    15391
    15392 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
    15393 assert(varexpr != NULL);
    15394 assert(SCIPisExprVar(scip, varexpr));
    15395
    15396 /* use difftag to decide whether the variable belongs to the expression */
    15397 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
    15398}
    15399
    15400/** returns the var's coordinate of Hu partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
    15401 *
    15402 * @see SCIPexprGetBardot()
    15403 */
    15405 SCIP* scip, /**< SCIP data structure */
    15406 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
    15407 SCIP_VAR* var /**< variable (needs to be in the expression) */
    15408 )
    15409{
    15410 SCIP_EXPR_OWNERDATA* ownerdata;
    15411 SCIP_CONSHDLRDATA* conshdlrdata;
    15412 SCIP_EXPR* varexpr;
    15413
    15414 assert(scip != NULL);
    15415 assert(expr != NULL);
    15416 assert(var != NULL);
    15417
    15418 /* return 0.0 for value expression */
    15419 if( SCIPisExprValue(scip, expr) )
    15420 return 0.0;
    15421
    15422 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
    15423 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
    15424 return SCIP_INVALID;
    15425
    15426 ownerdata = SCIPexprGetOwnerData(expr);
    15427 assert(ownerdata != NULL);
    15428
    15429 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15430 assert(conshdlrdata != NULL);
    15431
    15432 /* use variable to expressions mapping which is stored in the constraint handler data;
    15433 * if this fails it means that we are asking for the var's component of H*u for a var
    15434 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
    15435 */
    15436 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
    15437
    15438 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
    15439 assert(varexpr != NULL);
    15440 assert(SCIPisExprVar(scip, varexpr));
    15441
    15442 /* use difftag to decide whether the variable belongs to the expression */
    15443 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
    15444}
    15445
    15446/** evaluates quadratic term in a solution w.r.t. auxiliary variables
    15447 *
    15448 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
    15449 */
    15451 SCIP* scip, /**< SCIP data structure */
    15452 SCIP_EXPR* expr, /**< quadratic expression */
    15453 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
    15454 )
    15455{
    15456 SCIP_Real auxvalue;
    15457 int nlinexprs;
    15458 SCIP_Real* lincoefs;
    15459 SCIP_EXPR** linexprs;
    15460 int nquadexprs;
    15461 int nbilinexprs;
    15462 int i;
    15463
    15464 assert(scip != NULL);
    15465 assert(expr != NULL);
    15466
    15467 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
    15468
    15469 /* linear terms */
    15470 for( i = 0; i < nlinexprs; ++i )
    15471 {
    15472 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
    15473 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
    15474 }
    15475
    15476 /* quadratic terms */
    15477 for( i = 0; i < nquadexprs; ++i )
    15478 {
    15479 SCIP_EXPR* quadexprterm;
    15480 SCIP_Real lincoef;
    15481 SCIP_Real sqrcoef;
    15482 SCIP_Real solval;
    15483
    15484 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
    15485
    15486 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
    15487
    15488 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
    15489 auxvalue += (lincoef + sqrcoef * solval) * solval;
    15490 }
    15491
    15492 /* bilinear terms */
    15493 for( i = 0; i < nbilinexprs; ++i )
    15494 {
    15495 SCIP_EXPR* expr1;
    15496 SCIP_EXPR* expr2;
    15497 SCIP_Real coef;
    15498
    15499 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
    15500
    15501 assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
    15502 assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
    15503 auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
    15504 }
    15505
    15506 return auxvalue;
    15507}
    15508
    15509/**@addtogroup PublicNlhdlrInterfaceMethods
    15510 * @{
    15511 */
    15512
    15513/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
    15515 SCIP* scip, /**< SCIP data structure */
    15516 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
    15517 const char* name, /**< name of nonlinear handler (must not be NULL) */
    15518 const char* desc, /**< description of nonlinear handler (can be NULL) */
    15519 int detectpriority, /**< detection priority of nonlinear handler */
    15520 int enfopriority, /**< enforcement priority of nonlinear handler */
    15521 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
    15522 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
    15523 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
    15524 )
    15525{
    15526 SCIP_CONSHDLR* conshdlr;
    15527 SCIP_CONSHDLRDATA* conshdlrdata;
    15528
    15529 assert(scip != NULL);
    15530 assert(nlhdlr != NULL);
    15531 assert(detect != NULL);
    15532
    15533 /* find myself */
    15534 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    15535 if( conshdlr == NULL )
    15536 {
    15537 SCIPerrorMessage("nonlinear constraint handler not found");
    15538 return SCIP_PLUGINNOTFOUND;
    15539 }
    15540
    15541 /* create nlhdlr */
    15542 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
    15543
    15544 /* include into constraint handler */
    15545 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15546 assert(conshdlrdata != NULL);
    15547
    15548 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
    15549
    15550 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
    15551 ++conshdlrdata->nnlhdlrs;
    15552
    15553 /* sort nonlinear handlers by detection priority, in decreasing order
    15554 * will happen in INIT, so only do when called late
    15555 */
    15556 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
    15557 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
    15558
    15559 return SCIP_OKAY;
    15560}
    15561
    15562/** get number of nonlinear handler */
    15564 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    15565 )
    15566{
    15567 SCIP_CONSHDLRDATA* conshdlrdata;
    15568
    15569 assert(conshdlr != NULL);
    15570
    15571 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15572 assert(conshdlrdata != NULL);
    15573
    15574 return conshdlrdata->nnlhdlrs;
    15575}
    15576
    15577/** get nonlinear handlers */
    15579 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    15580 )
    15581{
    15582 SCIP_CONSHDLRDATA* conshdlrdata;
    15583
    15584 assert(conshdlr != NULL);
    15585
    15586 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15587 assert(conshdlrdata != NULL);
    15588
    15589 return conshdlrdata->nlhdlrs;
    15590}
    15591
    15592/** returns a nonlinear handler of a given name (or NULL if not found) */
    15594 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    15595 const char* name /**< name of nonlinear handler */
    15596 )
    15597{
    15598 SCIP_CONSHDLRDATA* conshdlrdata;
    15599 int h;
    15600
    15601 assert(conshdlr != NULL);
    15602 assert(name != NULL);
    15603
    15604 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15605 assert(conshdlrdata != NULL);
    15606
    15607 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
    15608 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
    15609 return conshdlrdata->nlhdlrs[h];
    15610
    15611 return NULL;
    15612}
    15613
    15614/** gives expression data that a given nonlinear handler stored in an expression
    15615 *
    15616 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
    15617 */
    15619 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
    15620 SCIP_EXPR* expr /**< expression */
    15621 )
    15622{
    15623 SCIP_EXPR_OWNERDATA* ownerdata;
    15624 int e;
    15625
    15626 assert(nlhdlr != NULL);
    15627 assert(expr != NULL);
    15628
    15629 ownerdata = SCIPexprGetOwnerData(expr);
    15630 assert(ownerdata != NULL);
    15631
    15632 for( e = 0; e < ownerdata->nenfos; ++e )
    15633 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
    15634 return ownerdata->enfos[e]->nlhdlrexprdata;
    15635
    15636 return NULL;
    15637}
    15638
    15639/** @} */
    SCIP_DECL_CONSDELVARS(ConshdlrSubtour::scip_delvars)
    static GRAPHNODE ** active
    SCIP_VAR * h
    Definition: circlepacking.c:68
    SCIP_VAR * w
    Definition: circlepacking.c:67
    SCIP_VAR * a
    Definition: circlepacking.c:66
    SCIP_VAR ** y
    Definition: circlepacking.c:64
    SCIP_Real * r
    Definition: circlepacking.c:59
    SCIP_VAR ** x
    Definition: circlepacking.c:63
    Constraint handler for AND constraints, .
    constraint handler for bound disjunction constraints
    Constraint handler for linear constraints in their most general form, .
    static SCIP_Bool isBinaryProduct(SCIP *scip, SCIP_EXPR *expr)
    static SCIP_RETCODE createExprVar(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR **expr, SCIP_VAR *var)
    static SCIP_Real computeVertexPolyhedralMaxFacetError(SCIP *scip, SCIP_Bool overestimate, SCIP_Real *funvals, SCIP_Real *box, int nallvars, int nvars, int *nonfixedpos, SCIP_Real *facetcoefs, SCIP_Real facetconstant)
    static SCIP_Bool isEvenOperator(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *hasvalue, SCIP_Real *value)
    static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_EXPRITER *it, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_RESULT *result, SCIP_Bool *success)
    static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
    #define ENFOLOG(x)
    #define DIALOG_DESC
    static SCIP_RETCODE tryAddGadgetEvenOperatorVariable(SCIP *scip, SCIP_EXPR *evenopexpr, SCIP_EXPR *child, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_Bool hassymval, SCIP_Real symval, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_Bool *success)
    static SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
    #define CONSHDLR_NEEDSCONS
    #define CONSHDLR_SEPAFREQ
    static SCIP_RETCODE analyzeViolation(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Real *maxabsconsviol, SCIP_Real *maxrelconsviol, SCIP_Real *minauxviol, SCIP_Real *maxauxviol, SCIP_Real *maxvarboundviol)
    static SCIP_RETCODE presolveRedundantConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss, int *nchgbds)
    static SCIP_RETCODE enforceExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_RESULT *result)
    static SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
    static SCIP_RETCODE reversePropQueue(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool *infeasible, int *ntightenings)
    #define BRANCH_RANDNUMINITSEED
    static SCIP_RETCODE dropVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
    static SCIP_DECL_CONSCHECK(consCheckNonlinear)
    static SCIP_RETCODE forbidNonlinearVariablesMultiaggration(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
    static SCIP_RETCODE computeHyperplaneThreePoints(SCIP *scip, SCIP_Real a1, SCIP_Real a2, SCIP_Real a3, SCIP_Real b1, SCIP_Real b2, SCIP_Real b3, SCIP_Real c1, SCIP_Real c2, SCIP_Real c3, SCIP_Real *alpha, SCIP_Real *beta, SCIP_Real *gamma_, SCIP_Real *delta)
    static SCIP_RETCODE propagateLocks(SCIP *scip, SCIP_EXPR *expr, int nlockspos, int nlocksneg)
    static SCIP_DECL_CONSPRINT(consPrintNonlinear)
    #define CONSHDLR_CHECKPRIORITY
    static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
    #define CONSHDLR_DESC
    static SCIP_DECL_CONSENABLE(consEnableNonlinear)
    static SCIP_RETCODE bilinTermAddAuxExpr(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSNONLINEAR_BILINTERM *term, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_Bool *added)
    static SCIP_RETCODE freeVarExprs(SCIP *scip, SCIP_CONSDATA *consdata)
    #define DIALOG_NAME
    static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
    static void scoreBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, SCIP_SOL *sol)
    #define consRespropNonlinear
    static SCIP_DECL_CONSPARSE(consParseNonlinear)
    static SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
    static SCIP_RETCODE consSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
    #define CONSHDLR_PROP_TIMING
    static void addExprsViolScore(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
    static SCIP_RETCODE tightenAuxVarBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *expr, SCIP_INTERVAL bounds, SCIP_Bool *cutoff, int *ntightenings)
    static SCIP_DECL_CONSLOCK(consLockNonlinear)
    #define TABLE_DESC_NLHDLR
    static SCIP_DECL_CONSPRESOL(consPresolNonlinear)
    static SCIP_RETCODE replaceBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_HASHMAP *exprmap, SCIP_EXPRITER *it, int *naddconss, int *nchgcoefs)
    static SCIP_RETCODE computeVertexPolyhedralFacetBivariate(SCIP *scip, SCIP_Bool overestimate, SCIP_Real p1[2], SCIP_Real p2[2], SCIP_Real p3[2], SCIP_Real p4[2], SCIP_Real p1val, SCIP_Real p2val, SCIP_Real p3val, SCIP_Real p4val, SCIP_Real xstar[2], SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
    static SCIP_RETCODE tryAddGadgetEvenOperator(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
    #define consInitpreNonlinear
    static SCIP_RETCODE addExprViolScoresAuxVars(SCIP *scip, SCIP_EXPR *expr, SCIP_Real violscore, SCIP_VAR **auxvars, int nauxvars, SCIP_SOL *sol, SCIP_Bool *success)
    static SCIP_RETCODE detectNlhdlr(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons)
    #define CONSHDLR_MAXPREROUNDS
    static SCIP_RETCODE computeVertexPolyhedralFacetLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_Real *xstar, SCIP_Real *box, int nallvars, int *nonfixedpos, SCIP_Real *funvals, int nvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
    static SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
    static SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
    #define TABLE_EARLIEST_STAGE_NLHDLR
    #define VERTEXPOLY_RANDNUMINITSEED
    static SCIP_DECL_CONSINIT(consInitNonlinear)
    static SCIP_RETCODE getFactorizedBinaryQuadraticExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *sumexpr, int minterms, SCIP_EXPR **newexpr, int *naddconss)
    #define consDelvarsNonlinear
    static SCIP_RETCODE reformulateFactorizedBinaryQuadratic(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_VAR *facvar, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_EXPR **newexpr, int *naddconss)
    #define CONSHDLR_SEPAPRIORITY
    static SCIP_RETCODE getConsRelViolation(SCIP *scip, SCIP_CONS *cons, SCIP_Real *viol, SCIP_SOL *sol, SCIP_Longint soltag)
    #define consGetDiveBdChgsNonlinear
    static SCIP_Bool isConsViolated(SCIP *scip, SCIP_CONS *cons)
    static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
    static SCIP_RETCODE getBinaryProductExprDo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, SCIP_Bool empathy4and)
    static SCIP_RETCODE registerBranchingCandidatesAllUnfixed(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
    static SCIP_Bool isIntervalBetter(SCIP *scip, SCIP_Bool subsetsufficient, SCIP_INTERVAL newinterval, SCIP_INTERVAL oldinterval)
    static SCIP_RETCODE detectNlhdlrs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
    #define TABLE_EARLIEST_STAGE_NONLINEAR
    static SCIP_RETCODE getBinaryProductExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_HASHMAP *exprmap, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, int *nchgcoefs)
    static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
    static SCIP_DECL_EVENTEXEC(processVarEvent)
    #define TABLE_DESC_NONLINEAR
    static SCIP_RETCODE createAuxVar(SCIP *scip, SCIP_EXPR *expr)
    static SCIP_Real getViolSplitWeight(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var, SCIP_SOL *sol)
    static SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
    static SCIP_RETCODE freeEnfoData(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool freeauxvar)
    #define infty2infty(infty1, infty2, val)
    static SCIP_RETCODE getBilinearBinaryTerms(SCIP *scip, SCIP_EXPR *sumexpr, SCIP_VAR **xs, SCIP_VAR **ys, int *childidxs, int *nterms)
    static SCIP_RETCODE storeVarExprs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata)
    static SCIP_RETCODE buildVertexPolyhedralSeparationLP(SCIP *scip, int nvars, SCIP_LPI **lp)
    static SCIP_RETCODE tryAddGadgetSquaredDifference(SCIP *scip, SCIP_EXPR *sumexpr, SCIP_CONS *cons, SYM_GRAPH *graph, int sumnodeidx, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs)
    static SCIP_RETCODE tryAddGadgetBilinearProductSignedPerm(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
    static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
    static SCIP_RETCODE propConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool force, SCIP_RESULT *result, int *nchgbds)
    static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss)
    static SCIP_RETCODE forwardPropExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *rootexpr, SCIP_Bool tightenauxvars, SCIP_Bool *infeasible, int *ntightenings)
    static SCIP_RETCODE consEnfo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
    static SCIP_Bool isSingleLockedCand(SCIP *scip, SCIP_EXPR *expr)
    static SCIP_DECL_CONSCOPY(consCopyNonlinear)
    static SCIP_Bool branchAuxNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
    static SCIP_RETCODE presolveImplint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nchgvartypes, SCIP_Bool *infeasible)
    #define TABLE_NAME_NONLINEAR
    static SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
    #define TABLE_NAME_NLHDLR
    static SCIP_RETCODE tryAddGadgetEvenOperatorSum(SCIP *scip, SCIP_EXPR *evenopexpr, SCIP_EXPR *child, SCIP_CONS *cons, SYM_GRAPH *graph, int parentidx, SCIP_Bool hasparentcoef, SCIP_Real parentcoef, SCIP_Bool hassymval, SCIP_Real symval, SCIP_VAR ***consvars, SCIP_Real **consvals, int *maxnconsvars, SCIP_HASHSET *handledexprs, SCIP_Bool *success)
    static SCIP_Real getDualBranchscore(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
    static SCIP_DECL_CONSINITLP(consInitlpNonlinear)
    static SCIP_RETCODE deinitSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
    static SCIP_RETCODE ensureLocVarsArraySize(SCIP *scip, SCIP_VAR ***vars, SCIP_Real **vals, int nelems, int *maxnelems)
    static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
    static SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
    static SCIP_RETCODE enforceExprNlhdlr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_SOL *sol, SCIP_Real auxvalue, SCIP_Bool overestimate, SCIP_Bool separated, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_RESULT *result)
    static SCIP_RETCODE selectBranchingCandidate(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, SCIP_SOL *sol, BRANCHCAND **selected)
    static SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
    static SCIP_RETCODE scaleConsSides(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *changed)
    static SCIP_DECL_CONSTRANS(consTransNonlinear)
    static SCIP_DECL_CONSDISABLE(consDisableNonlinear)
    static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag)
    static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
    #define VERTEXPOLY_MAXPERTURBATION
    static SCIP_RETCODE presolveBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddconss, int *nchgcoefs)
    static SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
    static SCIP_RETCODE catchVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
    static SCIP_RETCODE enforceConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_Real maxrelconsviol, SCIP_RESULT *result)
    static SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
    #define DIALOG_ISSUBMENU
    static SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
    static SCIP_DECL_TABLECOLLECT(tableCollectNonlinear)
    static SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
    static SCIP_RETCODE presolveSingleLockedVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *nchgvartypes, int *naddconss, SCIP_Bool *infeasible)
    static SCIP_DECL_CONSDELETE(consDeleteNonlinear)
    #define VERTEXPOLY_USEDUALSIMPLEX
    #define CONSHDLR_PROPFREQ
    static SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
    static SCIP_Bool varIsCenteredAt0(SCIP *scip, SCIP_VAR *var)
    static SCIP_RETCODE initSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *infeasible)
    static SCIP_RETCODE computeVertexPolyhedralFacetUnivariate(SCIP *scip, SCIP_Real left, SCIP_Real right, SCIP_Real funleft, SCIP_Real funright, SCIP_Bool *success, SCIP_Real *facetcoef, SCIP_Real *facetconstant)
    #define POWEROFTWO(x)
    #define CONSHDLR_PRESOLTIMING
    static SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
    static SCIP_RETCODE collectBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, BRANCHCAND *cands, int *ncands)
    static SCIP_RETCODE branching(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_RESULT *result)
    static SCIP_RETCODE bilinearTermsInsertAll(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
    #define VERTEXPOLY_ADJUSTFACETFACTOR
    #define TABLE_POSITION_NONLINEAR
    static SCIP_RETCODE initSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
    static SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
    static SCIP_RETCODE removeSingleLockedVars(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRITER *it, SCIP_HASHMAP *exprcands)
    #define CONSHDLR_EAGERFREQ
    static SCIP_RETCODE branchingIntegralOrNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Longint soltag, SCIP_Real maxrelconsviol, SCIP_Bool *branchintegral, SCIP_Bool *cutoff)
    static SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
    static SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
    static void findUnlockedLinearVar(SCIP *scip, SCIP_CONS *cons)
    static SCIP_RETCODE addLocks(SCIP *scip, SCIP_CONS *cons, int nlockspos, int nlocksneg)
    static SCIP_RETCODE propExprDomains(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds)
    static SCIP_RETCODE freeAuxVar(SCIP *scip, SCIP_EXPR *expr)
    static SCIP_Real getConsAbsViolation(SCIP_CONS *cons)
    static SCIP_RETCODE bilinearTermsFree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
    #define CONSHDLR_ENFOPRIORITY
    static SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
    static SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
    #define CONSHDLR_DELAYSEPA
    static SCIP_DECL_CONSACTIVE(consActiveNonlinear)
    static SCIP_DECL_SORTINDCOMP(branchcandCompare)
    static SCIP_Bool branchingIntegralFirst(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol)
    static SCIP_RETCODE createCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool copyexpr, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
    static SCIP_RETCODE bilinearTermsInsertEntry(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, int nlockspos, int nlocksneg, int *idx, SCIP_Bool existing)
    static SCIP_RETCODE notifyNlhdlrNewsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool solisbest)
    static SCIP_Real getExprAbsOrigViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
    #define CONSHDLR_NAME
    static SCIP_RETCODE presolveMergeConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
    static SCIP_Real getDomainCenter(SCIP *scip, SCIP_VAR *var)
    #define TABLE_POSITION_NLHDLR
    static SCIP_RETCODE ensureOpenArraySizeSymdetect(SCIP *scip, int **openidx, int nelems, int *maxnelems)
    static SCIP_RETCODE canonicalizeConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_PRESOLTIMING presoltiming, SCIP_Bool *infeasible, int *ndelconss, int *naddconss, int *nchgcoefs)
    static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
    static SCIP_DECL_CONSFREE(consFreeNonlinear)
    static SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
    static SCIP_Real getExprAbsAuxViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
    static SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
    static SCIP_DECL_CONSEXIT(consExitNonlinear)
    #define CONSHDLR_DELAYPROP
    static SCIP_DECL_CONSPROP(consPropNonlinear)
    static SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
    #define BILIN_MAXNAUXEXPRS
    constraint handler for nonlinear constraints specified by algebraic expressions
    Constraint handler for the set partitioning / packing / covering constraints .
    Constraint handler for variable bound constraints .
    methods for debugging
    #define SCIPdebugGetSolVal(scip, var, val)
    Definition: debug.h:313
    #define SCIPdebugAddSolVal(scip, var, val)
    Definition: debug.h:312
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_Longint
    Definition: def.h:150
    #define EPSROUND(x, eps)
    Definition: def.h:202
    #define EPSISINT(x, eps)
    Definition: def.h:204
    #define SCIP_REAL_MAX
    Definition: def.h:167
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_INTERVAL_INFINITY
    Definition: def.h:189
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define MAX3(x, y, z)
    Definition: def.h:237
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define ABS(x)
    Definition: def.h:225
    #define EPSFRAC(x, eps)
    Definition: def.h:203
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:343
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:157
    #define SCIPABORT()
    Definition: def.h:336
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    default user interface dialog
    absolute expression handler
    power and signed power expression handlers
    sum expression handler
    handler for sin expressions
    constant value expression handler
    variable expression handler
    handler for variable index expressions
    SCIP_Real SCIPevalBilinAuxExprNonlinear(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_SOL *sol)
    SCIP_RETCODE SCIPcheckQuadraticNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *isquadratic)
    SCIP_RETCODE SCIPaddLinearVarNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
    #define SCIP_DECL_NONLINCONSUPGD(x)
    SCIP_RETCODE SCIPmarkExprPropagateNonlinear(SCIP *scip, SCIP_EXPR *expr)
    SCIP_RETCODE SCIPcreateConsBasicSignpowerNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *x, SCIP_VAR *z, SCIP_Real exponent, SCIP_Real xoffset, SCIP_Real zcoef, SCIP_Real lhs, SCIP_Real rhs)
    SCIP_Real SCIPgetExprViolScoreNonlinear(SCIP_EXPR *expr)
    unsigned int SCIPgetExprNAuxvarUsesNonlinear(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPincludeConsUpgradeNonlinear(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
    void SCIPgetLinvarMayDecreaseNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **var, SCIP_Real *coef)
    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)
    int SCIPgetExprNLocksPosNonlinear(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPcreateConsBasicSOCNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *coefs, SCIP_Real *offsets, SCIP_Real constant, SCIP_VAR *rhsvar, SCIP_Real rhscoeff, SCIP_Real rhsoffset)
    SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    SCIP_RETCODE SCIPcreateConsBasicVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs)
    SCIP_RETCODE SCIPchgLhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
    SCIP_HASHMAP * SCIPgetVarExprHashmapNonlinear(SCIP_CONSHDLR *conshdlr)
    SCIP_RETCODE SCIPinsertBilinearTermImplicitNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *auxvar, SCIP_Real coefx, SCIP_Real coefy, SCIP_Real coefaux, SCIP_Real cst, SCIP_Bool overestimate)
    void SCIPsetExprEnfoAuxValueNonlinear(SCIP_EXPR *expr, int idx, SCIP_Real auxvalue)
    SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    SCIP_RETCODE SCIPgetNlRowNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
    SCIP_RETCODE SCIPchgRhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
    SCIP_RETCODE SCIPgetAbsViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *viol)
    SCIP_RETCODE SCIPgetExprRelAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
    SCIP_Longint SCIPgetCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr)
    SCIP_Bool SCIPassumeConvexNonlinear(SCIP_CONSHDLR *conshdlr)
    SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
    int SCIPgetBilinTermIdxNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y)
    void SCIPgetLinvarMayIncreaseNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **var, SCIP_Real *coef)
    SCIP_RETCODE SCIPinsertBilinearTermExistingNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *auxvar, int nlockspos, int nlocksneg)
    SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
    SCIP_RETCODE SCIPaddExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_Real coef)
    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)
    SCIP_EXPR * SCIPgetExprNonlinear(SCIP_CONS *cons)
    SCIP_RETCODE SCIPgetExprAbsOrigViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
    SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateConsBasicSetcover(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
    Definition: cons_setppc.c:9649
    unsigned int SCIPgetExprNSepaUsesActivityNonlinear(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPcreateConsNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
    SCIP_RETCODE SCIPcreateConsBasicNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs)
    SCIP_RETCODE SCIPgetExprActivityNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
    int SCIPgetExprNEnfosNonlinear(SCIP_EXPR *expr)
    int SCIPgetExprNLocksNegNonlinear(SCIP_EXPR *expr)
    SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
    SCIP_RETCODE SCIPtightenExprIntervalNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_INTERVAL newbounds, SCIP_Bool *cutoff, int *ntightenings)
    SCIP_RETCODE SCIPaddExprsViolScoreNonlinear(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
    int SCIPgetNBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
    SCIP_Real SCIPgetExprPartialDiffNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_VAR *var)
    SCIP_Longint SCIPgetLastBoundRelaxTagNonlinear(SCIP_CONSHDLR *conshdlr)
    SCIP_RETCODE SCIPcollectBilinTermsNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
    SCIP_RETCODE SCIPregisterExprUsageNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool useauxvar, SCIP_Bool useactivityforprop, SCIP_Bool useactivityforsepabelow, SCIP_Bool useactivityforsepaabove)
    SCIP_RETCODE SCIPcomputeFacetVertexPolyhedralNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_DECL_VERTEXPOLYFUN((*function)), void *fundata, SCIP_Real *xstar, SCIP_Real *box, int nallvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
    SCIP_RETCODE SCIPcreateConsBasicQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs)
    SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y)
    #define SCIP_DECL_VERTEXPOLYFUN(f)
    SCIP_RETCODE SCIPgetRelViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *viol)
    SCIP_INTERVAL SCIPgetExprBoundsNonlinear(SCIP *scip, SCIP_EXPR *expr)
    SCIP_RETCODE SCIPcreateConsBasicAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars)
    Definition: cons_and.c:5180
    unsigned int SCIPgetExprNPropUsesActivityNonlinear(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
    SCIP_RETCODE SCIPchgExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr)
    SCIP_EXPRCURV SCIPgetCurvatureNonlinear(SCIP_CONS *cons)
    SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
    void SCIPaddExprViolScoreNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real violscore)
    SCIP_RETCODE SCIPcreateConsBasicSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
    Definition: cons_setppc.c:9591
    void SCIPincrementCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_Bool boundrelax)
    SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
    SCIP_Real SCIPevalExprQuadraticAuxNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol)
    #define SCIP_MAXVERTEXPOLYDIM
    SCIP_Real SCIPgetExprPartialDiffGradientDirNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_VAR *var)
    SCIP_RETCODE SCIPincludeConshdlrNonlinear(SCIP *scip)
    SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_var.c:397
    SCIP_Bool SCIPisExprVaridx(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_varidx.c:252
    SCIP_Bool SCIPisExprAbs(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_abs.c:546
    SCIP_RETCODE SCIPappendExprSumExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *child, SCIP_Real childcoef)
    Definition: expr_sum.c:1154
    SCIP_RETCODE SCIPcreateExprSignpower(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_pow.c:3210
    SCIP_Bool SCIPisExprSignpower(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_pow.c:3235
    SCIP_Bool SCIPisExprCos(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_trig.c:1481
    SCIP_RETCODE SCIPcreateExprSum(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefficients, SCIP_Real constant, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_sum.c:1117
    SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_value.c:274
    SCIP_RETCODE SCIPcreateExprPow(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_pow.c:3186
    SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
    Definition: scip_general.c:676
    SCIP_STATUS SCIPgetStatus(SCIP *scip)
    Definition: scip_general.c:562
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    int SCIPgetNObjVars(SCIP *scip)
    Definition: scip_prob.c:2616
    SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_prob.c:1907
    int SCIPgetNIntVars(SCIP *scip)
    Definition: scip_prob.c:2340
    int SCIPgetNImplVars(SCIP *scip)
    Definition: scip_prob.c:2387
    int SCIPgetNContVars(SCIP *scip)
    Definition: scip_prob.c:2569
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3420
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    int SCIPgetNBinVars(SCIP *scip)
    Definition: scip_prob.c:2293
    int SCIPgetNTotalVars(SCIP *scip)
    Definition: scip_prob.c:3064
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    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 SCIPhashmapGetNElements(SCIP_HASHMAP *hashmap)
    Definition: misc.c:3576
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3179
    SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3482
    void SCIPhashsetFree(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem)
    Definition: misc.c:3833
    SCIP_Bool SCIPhashsetExists(SCIP_HASHSET *hashset, void *element)
    Definition: misc.c:3860
    SCIP_Bool SCIPhashsetIsEmpty(SCIP_HASHSET *hashset)
    Definition: misc.c:4027
    SCIP_RETCODE SCIPhashsetInsert(SCIP_HASHSET *hashset, BMS_BLKMEM *blkmem, void *element)
    Definition: misc.c:3843
    SCIP_RETCODE SCIPhashsetCreate(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem, int size)
    Definition: misc.c:3802
    SCIP_RETCODE SCIPhashsetRemove(SCIP_HASHSET *hashset, void *element)
    Definition: misc.c:3901
    void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
    Definition: misc.c:2348
    #define SCIPhashTwo(a, b)
    Definition: pub_misc.h:568
    SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
    Definition: misc.c:2298
    void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
    Definition: misc.c:2596
    SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
    Definition: misc.c:2535
    SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
    Definition: lpi_clp.cpp:1179
    SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:3947
    SCIP_RETCODE SCIPlpiChgObjsen(SCIP_LPI *lpi, SCIP_OBJSEN objsen)
    Definition: lpi_clp.cpp:1232
    SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI *lpi, SCIP_LPPARAM type, SCIP_Real dval)
    Definition: lpi_clp.cpp:3861
    SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
    Definition: lpi_clp.cpp:643
    SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:2637
    SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
    Definition: lpi_clp.cpp:3720
    SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
    Definition: lpi_clp.cpp:2816
    SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:1908
    SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
    Definition: lpi_clp.cpp:1833
    SCIP_RETCODE SCIPlpiLoadColLP(SCIP_LPI *lpi, SCIP_OBJSEN objsen, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
    Definition: lpi_clp.cpp:677
    SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
    Definition: lpi_clp.cpp:531
    SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
    Definition: lpi_clp.cpp:1252
    SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
    Definition: lpi_clp.cpp:1447
    SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
    Definition: lpi_clp.cpp:1429
    SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:4067
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    #define SCIPdebugMsgPrint
    Definition: scip_message.h:79
    SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
    Definition: scip_message.c:88
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    void SCIPdialogMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:191
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    SCIP_RETCODE SCIPhasExprCurvature(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRCURV curv, SCIP_Bool *success, SCIP_HASHMAP *assumevarfixed)
    SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
    Definition: heur_trysol.c:259
    SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
    Definition: heur_subnlp.c:1938
    SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:167
    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
    SCIP_RETCODE SCIPgetCharParam(SCIP *scip, const char *name, char *value)
    Definition: scip_param.c:326
    void SCIPswapPointers(void **pointer1, void **pointer2)
    Definition: misc.c:10511
    void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
    Definition: misc.c:10498
    SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
    Definition: scip_branch.c:673
    SCIP_Real SCIPgetBranchingPoint(SCIP *scip, SCIP_VAR *var, SCIP_Real suggestion)
    Definition: scip_branch.c:905
    SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
    Definition: scip_branch.c:1134
    SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
    Definition: scip_branch.c:402
    int SCIPgetNLPBranchCands(SCIP *scip)
    Definition: scip_branch.c:436
    SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
    Definition: scip_branch.c:857
    SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
    Definition: lp.c:17545
    int SCIPcolGetNLPNonz(SCIP_COL *col)
    Definition: lp.c:17534
    SCIP_Bool SCIPcolIsInLP(SCIP_COL *col)
    Definition: lp.c:17509
    void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
    Definition: cons.c:4350
    int SCIPconshdlrGetMaxNActiveConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:5116
    int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4782
    const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4320
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4340
    SCIP_RETCODE SCIPincludeConshdlr(SCIP *scip, const char *name, const char *desc, int sepapriority, int enfopriority, int chckpriority, int sepafreq, int propfreq, int eagerfreq, int maxprerounds, SCIP_Bool delaysepa, SCIP_Bool delayprop, SCIP_Bool needscons, SCIP_PROPTIMING proptiming, SCIP_PRESOLTIMING presoltiming, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSFREE((*consfree)), SCIP_DECL_CONSINIT((*consinit)), SCIP_DECL_CONSEXIT((*consexit)), SCIP_DECL_CONSINITPRE((*consinitpre)), SCIP_DECL_CONSEXITPRE((*consexitpre)), SCIP_DECL_CONSINITSOL((*consinitsol)), SCIP_DECL_CONSEXITSOL((*consexitsol)), SCIP_DECL_CONSDELETE((*consdelete)), SCIP_DECL_CONSTRANS((*constrans)), SCIP_DECL_CONSINITLP((*consinitlp)), SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFORELAX((*consenforelax)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSPROP((*consprop)), SCIP_DECL_CONSPRESOL((*conspresol)), SCIP_DECL_CONSRESPROP((*consresprop)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_DECL_CONSACTIVE((*consactive)), SCIP_DECL_CONSDEACTIVE((*consdeactive)), SCIP_DECL_CONSENABLE((*consenable)), SCIP_DECL_CONSDISABLE((*consdisable)), SCIP_DECL_CONSDELVARS((*consdelvars)), SCIP_DECL_CONSPRINT((*consprint)), SCIP_DECL_CONSCOPY((*conscopy)), SCIP_DECL_CONSPARSE((*consparse)), SCIP_DECL_CONSGETVARS((*consgetvars)), SCIP_DECL_CONSGETNVARS((*consgetnvars)), SCIP_DECL_CONSGETDIVEBDCHGS((*consgetdivebdchgs)), SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)), SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)), SCIP_CONSHDLRDATA *conshdlrdata)
    Definition: scip_cons.c:83
    SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4739
    SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
    Definition: cons.c:8423
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8652
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8413
    SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
    Definition: cons.c:8511
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8562
    SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
    Definition: scip_cons.c:2536
    SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
    Definition: cons.c:8692
    SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
    Definition: cons.c:8592
    SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
    Definition: cons.c:8522
    SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
    Definition: cons.c:8702
    SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
    Definition: cons.c:8582
    SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
    Definition: cons.c:8454
    SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    Definition: scip_cons.c:997
    SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
    Definition: cons.c:8612
    SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
    Definition: cons.c:8632
    SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
    Definition: cons.c:8490
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8393
    SCIP_Bool SCIPconsIsSeparationEnabled(SCIP_CONS *cons)
    Definition: cons.c:8500
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8642
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8572
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8662
    SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:94
    SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:117
    SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
    Definition: scip_cut.c:207
    SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
    Definition: scip_cut.c:225
    SCIP_RETCODE SCIPinsertDatatreeLong(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Longint value)
    SCIP_RETCODE SCIPinsertDatatreeReal(SCIP *scip, SCIP_DATATREE *datatree, const char *name, SCIP_Real value)
    SCIP_RETCODE SCIPreleaseDialog(SCIP *scip, SCIP_DIALOG **dialog)
    Definition: scip_dialog.c:124
    SCIP_DIALOG * SCIPdialoghdlrGetRoot(SCIP_DIALOGHDLR *dialoghdlr)
    Definition: dialog.c:436
    SCIP_Bool SCIPdialogHasEntry(SCIP_DIALOG *dialog, const char *entryname)
    Definition: dialog.c:1013
    SCIP_RETCODE SCIPdialoghdlrAddHistory(SCIP_DIALOGHDLR *dialoghdlr, SCIP_DIALOG *dialog, const char *command, SCIP_Bool escapecommand)
    Definition: dialog.c:725
    SCIP_RETCODE SCIPincludeDialog(SCIP *scip, SCIP_DIALOG **dialog, SCIP_DECL_DIALOGCOPY((*dialogcopy)), SCIP_DECL_DIALOGEXEC((*dialogexec)), SCIP_DECL_DIALOGDESC((*dialogdesc)), SCIP_DECL_DIALOGFREE((*dialogfree)), const char *name, const char *desc, SCIP_Bool issubmenu, SCIP_DIALOGDATA *dialogdata)
    Definition: scip_dialog.c:59
    SCIP_RETCODE SCIPaddDialogEntry(SCIP *scip, SCIP_DIALOG *dialog, SCIP_DIALOG *subdialog)
    Definition: scip_dialog.c:171
    SCIP_DIALOG * SCIPgetRootDialog(SCIP *scip)
    Definition: scip_dialog.c:157
    int SCIPdialogFindEntry(SCIP_DIALOG *dialog, const char *entryname, SCIP_DIALOG **subdialog)
    Definition: dialog.c:1046
    int SCIPgetPtrarrayMinIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
    void * SCIPgetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx)
    SCIP_RETCODE SCIPfreePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
    int SCIPgetPtrarrayMaxIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
    SCIP_RETCODE SCIPcreatePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
    SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
    Definition: scip_event.c:111
    SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
    Definition: scip_event.c:241
    SCIP_IMPLINTTYPE SCIPeventGetNewImpltype(SCIP_EVENT *event)
    Definition: event.c:1513
    SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
    Definition: event.c:1194
    SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
    Definition: event.c:1567
    SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
    Definition: scip_event.c:367
    SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
    Definition: scip_event.c:413
    SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
    Definition: event.c:1217
    SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
    Definition: scip_event.c:293
    SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
    Definition: scip_event.c:333
    const char * SCIPexprhdlrGetName(SCIP_EXPRHDLR *exprhdlr)
    Definition: expr.c:545
    SCIP_Bool SCIPexprhdlrHasGetSymData(SCIP_EXPRHDLR *exprhdlr)
    Definition: expr.c:685
    SCIP_Bool SCIPexprhdlrHasMonotonicity(SCIP_EXPRHDLR *exprhdlr)
    Definition: expr.c:665
    SCIP_Bool SCIPexprhdlrHasReverseProp(SCIP_EXPRHDLR *exprhdlr)
    Definition: expr.c:675
    void SCIPexprSetActivity(SCIP_EXPR *expr, SCIP_INTERVAL activity, SCIP_Longint activitytag)
    Definition: expr.c:4054
    SCIP_RETCODE SCIPcreateExprQuadratic(SCIP *scip, SCIP_EXPR **expr, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: scip_expr.c:1059
    SCIP_IMPLINTTYPE SCIPexprGetIntegrality(SCIP_EXPR *expr)
    Definition: expr.c:4091
    SCIP_RETCODE SCIPgetSymDataExpr(SCIP *scip, SCIP_EXPR *expr, SYM_EXPRDATA **symdata)
    Definition: scip_expr.c:1817
    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
    void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
    Definition: expr.c:4226
    SCIP_RETCODE SCIPcomputeExprIntegrality(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:2040
    SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
    Definition: expr_pow.c:3449
    SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1490
    SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
    Definition: scip_expr.c:1692
    SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
    Definition: expriter.c:969
    SCIP_Longint SCIPgetExprNewSoltag(SCIP *scip)
    Definition: scip_expr.c:1677
    SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
    Definition: expriter.c:930
    SCIP_EXPR_OWNERDATA * SCIPexprGetOwnerData(SCIP_EXPR *expr)
    Definition: expr.c:3933
    SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
    Definition: expr.c:3972
    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_Longint SCIPexprGetEvalTag(SCIP_EXPR *expr)
    Definition: expr.c:3959
    SCIP_Bool SCIPexprIsIntegral(SCIP_EXPR *expr)
    Definition: expr.c:4101
    SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
    Definition: expr.c:4262
    void SCIPexprGetQuadraticData(SCIP_EXPR *expr, SCIP_Real *constant, int *nlinexprs, SCIP_EXPR ***linexprs, SCIP_Real **lincoefs, int *nquadexprs, int *nbilinexprs, SCIP_Real **eigenvalues, SCIP_Real **eigenvectors)
    Definition: expr.c:4141
    SCIP_RETCODE SCIPreplaceExprChild(SCIP *scip, SCIP_EXPR *expr, int childidx, SCIP_EXPR *newchild)
    Definition: scip_expr.c:1274
    SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
    Definition: expr_sum.c:1554
    SCIP_EXPRITER_USERDATA SCIPexpriterGetCurrentUserData(SCIP_EXPRITER *iterator)
    Definition: expriter.c:756
    SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1468
    SCIP_Real SCIPgetCoefExprProduct(SCIP_EXPR *expr)
    void SCIPfreeExprQuadratic(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:2420
    SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
    Definition: scip_expr.c:1443
    SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
    Definition: expriter.c:683
    void SCIPexpriterSetStagesDFS(SCIP_EXPRITER *iterator, SCIP_EXPRITER_STAGE stopstages)
    Definition: expriter.c:664
    SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1457
    SCIP_RETCODE SCIPparseExpr(SCIP *scip, SCIP_EXPR **expr, const char *exprstr, const char **finalpos, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: scip_expr.c:1406
    SCIP_EXPR * SCIPexpriterRestartDFS(SCIP_EXPRITER *iterator, SCIP_EXPR *expr)
    Definition: expriter.c:630
    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_EXPR * SCIPexpriterGetParentDFS(SCIP_EXPRITER *iterator)
    Definition: expriter.c:740
    SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
    Definition: expr_value.c:298
    void SCIPexpriterSetCurrentUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
    Definition: expriter.c:806
    SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1501
    SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
    Definition: expr.c:3946
    SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
    Definition: expr.c:4044
    SCIP_RETCODE SCIPreplaceCommonSubexpressions(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Bool *replacedroot)
    Definition: scip_expr.c:1845
    SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
    Definition: expriter.c:858
    SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
    Definition: scip_expr.c:2402
    SCIP_Real SCIPexprGetBardot(SCIP_EXPR *expr)
    Definition: expr.c:4000
    SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
    Definition: expr.c:3882
    SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
    Definition: expr_sum.c:1569
    SCIP_RETCODE SCIPcopyExpr(SCIP *sourcescip, SCIP *targetscip, SCIP_EXPR *expr, SCIP_EXPR **copyexpr, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *valid)
    Definition: scip_expr.c:1344
    SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
    Definition: expr_var.c:423
    void SCIPexpriterSetChildUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
    Definition: expriter.c:838
    SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
    Definition: expr.c:4028
    void SCIPexprGetQuadraticQuadTerm(SCIP_EXPR *quadexpr, int termidx, SCIP_EXPR **expr, SCIP_Real *lincoef, SCIP_Real *sqrcoef, int *nadjbilin, int **adjbilin, SCIP_EXPR **sqrexpr)
    Definition: expr.c:4186
    int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
    Definition: expriter.c:707
    void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2376
    SCIP_EXPRITER_STAGE SCIPexpriterGetStageDFS(SCIP_EXPRITER *iterator)
    Definition: expriter.c:696
    void SCIPexprSetIntegrality(SCIP_EXPR *expr, SCIP_IMPLINTTYPE integrality)
    Definition: expr.c:4111
    SCIP_RETCODE SCIPduplicateExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **copyexpr, SCIP_DECL_EXPR_MAPEXPR((*mapexpr)), void *mapexprdata, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: scip_expr.c:1307
    void SCIPcaptureExpr(SCIP_EXPR *expr)
    Definition: scip_expr.c:1435
    SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
    Definition: expriter.c:501
    int SCIPexprGetNUses(SCIP_EXPR *expr)
    Definition: expr.c:3862
    SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
    Definition: scip_expr.c:2121
    SCIP_Longint SCIPexprGetDiffTag(SCIP_EXPR *expr)
    Definition: expr.c:4015
    SCIP_RETCODE SCIPsimplifyExpr(SCIP *scip, SCIP_EXPR *rootexpr, SCIP_EXPR **simplified, SCIP_Bool *changed, SCIP_Bool *infeasible, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: scip_expr.c:1798
    SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1742
    SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
    Definition: expr.c:3895
    SCIP_EXPR * SCIPexpriterGetChildExprDFS(SCIP_EXPRITER *iterator)
    Definition: expriter.c:721
    SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
    Definition: scip_heur.c:263
    const char * SCIPheurGetName(SCIP_HEUR *heur)
    Definition: heur.c:1467
    void SCIPintervalIntersectEps(SCIP_INTERVAL *resultant, SCIP_Real eps, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
    void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
    SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
    void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
    void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    SCIP_Real SCIPgetLPObjval(SCIP *scip)
    Definition: scip_lp.c:253
    void SCIPsetLPFeastol(SCIP *scip, SCIP_Real newfeastol)
    Definition: scip_lp.c:444
    SCIP_Real SCIPgetLPFeastol(SCIP *scip)
    Definition: scip_lp.c:434
    #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 SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
    Definition: scip_mem.h:107
    BMS_BUFMEM * SCIPbuffer(SCIP *scip)
    Definition: scip_mem.c:72
    #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
    SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
    Definition: scip_nlp.c:424
    SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
    Definition: scip_nlp.c:396
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    void SCIPenableNLP(SCIP *scip)
    Definition: scip_nlp.c:95
    SCIP_RETCODE SCIPsetNlRowExpr(SCIP *scip, SCIP_NLROW *nlrow, SCIP_EXPR *expr)
    Definition: scip_nlp.c:1248
    SCIP_RETCODE SCIPaddLinearCoefToNlRow(SCIP *scip, SCIP_NLROW *nlrow, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_nlp.c:1161
    SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
    Definition: scip_nlp.c:1058
    SCIP_RETCODE SCIPchgNlRowConstant(SCIP *scip, SCIP_NLROW *nlrow, SCIP_Real constant)
    Definition: scip_nlp.c:1126
    void SCIPsetNlRowCurvature(SCIP *scip, SCIP_NLROW *nlrow, SCIP_EXPRCURV curvature)
    Definition: scip_nlp.c:1140
    SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
    Definition: scip_nlp.c:954
    const char * SCIPnlhdlrGetDesc(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:177
    SCIP_NLHDLR ** SCIPgetNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
    SCIP_Bool SCIPnlhdlrHasIntEval(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:227
    int SCIPnlhdlrGetDetectPriority(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:187
    SCIP_NLHDLREXPRDATA * SCIPgetNlhdlrExprDataNonlinear(SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr)
    SCIP_Bool SCIPnlhdlrIsEnabled(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:207
    int SCIPgetNNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
    const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:167
    SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
    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_Bool SCIPnlhdlrHasInitSepa(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:247
    int SCIPnlhdlrGetEnfoPriority(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:197
    SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
    Definition: tree.c:8513
    SCIP_Bool SCIPinProbing(SCIP *scip)
    Definition: scip_probing.c:98
    SCIP_CONSHDLR * SCIProwGetOriginConshdlr(SCIP_ROW *row)
    Definition: lp.c:17850
    SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
    Definition: scip_lp.c:2176
    const char * SCIProwGetName(SCIP_ROW *row)
    Definition: lp.c:17745
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1814
    SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
    Definition: lp.c:17706
    SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
    Definition: scip_sepa.c:345
    SCIP_SOLORIGIN SCIPsolGetOrigin(SCIP_SOL *sol)
    Definition: sol.c:4145
    SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
    Definition: scip_sol.c:882
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1250
    SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
    Definition: sol.c:4274
    SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:606
    SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1504
    SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
    Definition: scip_sol.c:1717
    void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
    Definition: scip_sol.c:451
    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_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:2003
    SCIP_Real SCIPgetUpperbound(SCIP *scip)
    SCIP_Real SCIPgetAvgPseudocostCount(SCIP *scip, SCIP_BRANCHDIR dir)
    SCIP_TABLE * SCIPfindTable(SCIP *scip, const char *name)
    Definition: scip_table.c:101
    SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_DECL_TABLECOLLECT((*tablecollect)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
    Definition: scip_table.c:62
    SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
    Definition: scip_timing.c:76
    SCIP_RETCODE SCIPresetClock(SCIP *scip, SCIP_CLOCK *clck)
    Definition: scip_timing.c:144
    SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
    Definition: scip_timing.c:178
    SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
    Definition: scip_timing.c:127
    SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
    Definition: scip_timing.c:319
    SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
    Definition: scip_timing.c:161
    SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
    SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Real SCIPgetHugeValue(SCIP *scip)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPepsilon(SCIP *scip)
    SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
    Definition: scip_tree.c:91
    SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6401
    SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
    Definition: scip_var.c:5176
    SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
    Definition: var.c:23715
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
    Definition: scip_var.c:11350
    SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
    Definition: var.c:23418
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4380
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23530
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23538
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23932
    void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
    Definition: var.c:23650
    SCIP_RETCODE SCIPchgVarImplType(SCIP *scip, SCIP_VAR *var, SCIP_IMPLINTTYPE impltype, SCIP_Bool *infeasible)
    Definition: scip_var.c:10218
    SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6651
    SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
    Definition: var.c:23485
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23684
    SCIP_RETCODE SCIPcreateVarImpl(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_IMPLINTTYPE impltype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
    Definition: scip_var.c:225
    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 SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
    Definition: scip_var.c:5634
    SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
    Definition: scip_var.c:11188
    SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
    Definition: scip_var.c:5570
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23522
    SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
    Definition: scip_var.c:10113
    SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
    Definition: scip_var.c:2166
    int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24674
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24685
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:11057
    SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR *var)
    Definition: var.c:23495
    int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
    Definition: var.c:17319
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4322
    SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
    Definition: scip_var.c:2078
    SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:1853
    void SCIPqueueFree(SCIP_QUEUE **queue)
    Definition: misc.c:1019
    SCIP_RETCODE SCIPqueueCreate(SCIP_QUEUE **queue, int initsize, SCIP_Real sizefac)
    Definition: misc.c:995
    SCIP_RETCODE SCIPqueueInsert(SCIP_QUEUE *queue, void *elem)
    Definition: misc.c:1081
    SCIP_Bool SCIPqueueIsEmpty(SCIP_QUEUE *queue)
    Definition: misc.c:1236
    void * SCIPqueueRemove(SCIP_QUEUE *queue)
    Definition: misc.c:1132
    void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
    SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
    Definition: misc.c:10245
    SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
    int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
    Definition: misc.c:10223
    SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:639
    SCIP_RETCODE SCIPcleanupRowprep2(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefbound, SCIP_Bool *success)
    int SCIProwprepGetNModifiedVars(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:699
    SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Bool *reliable)
    Definition: misc_rowprep.c:972
    SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:649
    SCIP_VAR ** SCIProwprepGetModifiedVars(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:709
    char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:689
    SCIP_SIDETYPE SCIProwprepGetSidetype(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:669
    SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
    Definition: misc_rowprep.c:913
    SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
    int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:629
    void SCIProwprepRecordModifications(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:791
    SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real minviol, SCIP_Real *viol, SCIP_Bool *success)
    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 SCIPsortDown(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
    Definition: misc.c:6144
    void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
    void SCIPsortDownIntPtr(int *intarray, void **ptrarray, int len)
    void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
    Definition: misc.c:5581
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    SCIP_RETCODE SCIPskipSpace(char **s)
    Definition: misc.c:10816
    SCIP_RETCODE SCIPaddSymgraphEdge(SCIP *scip, SYM_GRAPH *graph, int first, int second, SCIP_Bool hasval, SCIP_Real val)
    SCIP_RETCODE SCIPaddSymgraphOpnode(SCIP *scip, SYM_GRAPH *graph, int op, int *nodeidx)
    SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
    SCIP_RETCODE SCIPaddSymgraphValnode(SCIP *scip, SYM_GRAPH *graph, SCIP_Real val, int *nodeidx)
    int SCIPgetSymgraphVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
    SCIP_RETCODE SCIPaddSymgraphConsnode(SCIP *scip, SYM_GRAPH *graph, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, int *nodeidx)
    SCIP_RETCODE SCIPaddSymgraphVarAggregation(SCIP *scip, SYM_GRAPH *graph, int rootidx, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real constant)
    int SCIPgetSymExprdataNConstants(SYM_EXPRDATA *symdata)
    int SCIPgetSymgraphNegatedVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
    SCIP_RETCODE SCIPfreeSymDataExpr(SCIP *scip, SYM_EXPRDATA **symdata)
    int SCIPgetSymgraphNNodes(SYM_GRAPH *graph)
    SCIP_Real * SCIPgetSymExprdataConstants(SYM_EXPRDATA *symdata)
    SCIP_RETCODE SCIPgetCoefSymData(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *parentexpr, SCIP_Real *coef, SCIP_Bool *success)
    NLP local search primal heuristic using sub-SCIPs.
    primal heuristic that tries a given solution
    SCIP_Bool SCIPcliqueHasVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
    Definition: implics.c:1141
    static volatile int nterms
    Definition: interrupt.c:47
    SCIP_Bool SCIPlapackIsAvailable(void)
    Definition: lapack_calls.c:121
    SCIP_RETCODE SCIPlapackSolveLinearEquations(BMS_BUFMEM *bufmem, int n, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x, SCIP_Bool *success)
    Definition: lapack_calls.c:386
    interface methods for lapack functions
    static const char * paramname[]
    Definition: lpi_msk.c:5172
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    SCIP_RETCODE SCIPnlhdlrFree(SCIP *scip, SCIP_NLHDLR **nlhdlr)
    Definition: nlhdlr.c:402
    SCIP_RETCODE SCIPnlhdlrCreate(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)
    Definition: nlhdlr.c:354
    void SCIPnlhdlrPrintStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, FILE *file)
    Definition: nlhdlr.c:756
    SCIP_RETCODE SCIPnlhdlrCollectStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, SCIP_DATATREE *datatree)
    Definition: nlhdlr.c:800
    private functions of nonlinear handlers of nonlinear constraints
    #define SCIPnlhdlrIncrementNSeparated(nlhdlr)
    Definition: nlhdlr.h:140
    #define SCIPnlhdlrResetNDetectionslast(nlhdlr)
    Definition: nlhdlr.h:138
    #define SCIPnlhdlrIncrementNCutoffs(nlhdlr)
    Definition: nlhdlr.h:139
    nonlinear handlers for convex and concave expressions, respectively
    SCIP_RETCODE SCIPgetSymOpNodeType(SCIP *scip, const char *opnodename, int *nodetype)
    propagator for symmetry handling
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebugPrintCons(x, y, z)
    Definition: pub_message.h:102
    #define SCIPisFinite(x)
    Definition: pub_misc.h:82
    methods for sorting joint arrays of various types
    public methods for data tree structure
    public functions to work with algebraic expressions
    static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
    Main separation function.
    Definition: sepa_flower.c:1219
    SCIP_Real dual
    SCIP_VAR * var
    SCIP_Real fractionality
    SCIP_Real vartype
    SCIP_Real pscost
    SCIP_Real domain
    SCIP_Real weighted
    SCIP_Real auxviol
    SCIP_EXPR * expr
    SCIP_DECL_NONLINCONSUPGD((*consupgd))
    SCIP_Bool active
    SCIP_NLHDLR_METHOD nlhdlrparticipation
    SCIP_NLHDLR * nlhdlr
    SCIP_Bool sepaaboveusesactivity
    SCIP_Bool sepabelowusesactivity
    SCIP_Bool issepainit
    SCIP_Real auxvalue
    SCIP_NLHDLREXPRDATA * nlhdlrexprdata
    SCIP_CONSNONLINEAR_AUXEXPR ** exprs
    union SCIP_ConsNonlinear_BilinTerm::@6 aux
    int nlockspos[NLOCKTYPES]
    Definition: struct_cons.h:64
    SCIP_Real sup
    Definition: intervalarith.h:57
    SCIP_Real inf
    Definition: intervalarith.h:56
    structs for symmetry computations
    methods for dealing with symmetry detection graphs
    #define SCIP_DECL_CONSINITPRE(x)
    Definition: type_cons.h:156
    struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
    Definition: type_cons.h:64
    #define SCIP_DECL_CONSGETDIVEBDCHGS(x)
    Definition: type_cons.h:920
    #define SCIP_DECL_CONSRESPROP(x)
    Definition: type_cons.h:612
    struct SCIP_ConsData SCIP_CONSDATA
    Definition: type_cons.h:65
    #define SCIP_EVENTTYPE_BOUNDCHANGED
    Definition: type_event.h:127
    #define SCIP_EVENTTYPE_TYPECHANGED
    Definition: type_event.h:86
    struct SCIP_EventData SCIP_EVENTDATA
    Definition: type_event.h:179
    #define SCIP_EVENTTYPE_VARFIXED
    Definition: type_event.h:72
    #define SCIP_EVENTTYPE_BESTSOLFOUND
    Definition: type_event.h:106
    #define SCIP_EVENTTYPE_FORMAT
    Definition: type_event.h:157
    #define SCIP_EVENTTYPE_BOUNDRELAXED
    Definition: type_event.h:126
    #define SCIP_EVENTTYPE_SOLFOUND
    Definition: type_event.h:146
    uint64_t SCIP_EVENTTYPE
    Definition: type_event.h:156
    #define SCIP_EVENTTYPE_IMPLTYPECHANGED
    Definition: type_event.h:87
    #define SCIP_EVENTTYPE_BOUNDTIGHTENED
    Definition: type_event.h:125
    SCIP_EXPRCURV
    Definition: type_expr.h:61
    @ SCIP_EXPRCURV_CONVEX
    Definition: type_expr.h:63
    @ SCIP_EXPRCURV_LINEAR
    Definition: type_expr.h:65
    @ SCIP_EXPRCURV_UNKNOWN
    Definition: type_expr.h:62
    @ SCIP_EXPRCURV_CONCAVE
    Definition: type_expr.h:64
    #define SCIP_EXPRITER_VISITINGCHILD
    Definition: type_expr.h:695
    struct SCIP_Expr_OwnerData SCIP_EXPR_OWNERDATA
    Definition: type_expr.h:80
    SCIP_MONOTONE
    Definition: type_expr.h:70
    @ SCIP_MONOTONE_CONST
    Definition: type_expr.h:74
    @ SCIP_MONOTONE_UNKNOWN
    Definition: type_expr.h:71
    @ SCIP_MONOTONE_INC
    Definition: type_expr.h:72
    @ SCIP_MONOTONE_DEC
    Definition: type_expr.h:73
    @ SCIP_EXPRITER_BFS
    Definition: type_expr.h:717
    @ SCIP_EXPRITER_DFS
    Definition: type_expr.h:718
    @ SCIP_EXPRITER_RTOPOLOGIC
    Definition: type_expr.h:716
    #define SCIP_EXPRITER_LEAVEEXPR
    Definition: type_expr.h:697
    #define SCIP_EXPRITER_ENTEREXPR
    Definition: type_expr.h:694
    @ SCIP_BRANCHDIR_DOWNWARDS
    Definition: type_history.h:43
    @ SCIP_BRANCHDIR_UPWARDS
    Definition: type_history.h:44
    @ SCIP_BOUNDTYPE_UPPER
    Definition: type_lp.h:58
    @ SCIP_BOUNDTYPE_LOWER
    Definition: type_lp.h:57
    enum SCIP_BoundType SCIP_BOUNDTYPE
    Definition: type_lp.h:60
    @ SCIP_SIDETYPE_RIGHT
    Definition: type_lp.h:66
    @ SCIP_SIDETYPE_LEFT
    Definition: type_lp.h:65
    @ SCIP_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_LPSOLSTAT_UNBOUNDEDRAY
    Definition: type_lp.h:46
    @ SCIP_LPPAR_LPINFO
    Definition: type_lpi.h:55
    @ SCIP_LPPAR_DUALFEASTOL
    Definition: type_lpi.h:57
    @ SCIP_LPPAR_FEASTOL
    Definition: type_lpi.h:56
    @ SCIP_LPPAR_LPITLIM
    Definition: type_lpi.h:60
    @ SCIP_LPPAR_OBJLIM
    Definition: type_lpi.h:59
    @ SCIP_OBJSEN_MAXIMIZE
    Definition: type_lpi.h:42
    @ SCIP_OBJSEN_MINIMIZE
    Definition: type_lpi.h:43
    #define SCIP_NLHDLR_METHOD_SEPAABOVE
    Definition: type_nlhdlr.h:52
    #define SCIP_DECL_NLHDLREVALAUX(x)
    Definition: type_nlhdlr.h:202
    struct SCIP_NlhdlrData SCIP_NLHDLRDATA
    Definition: type_nlhdlr.h:452
    #define SCIP_NLHDLR_METHOD_SEPABOTH
    Definition: type_nlhdlr.h:53
    #define SCIP_NLHDLR_METHOD_ACTIVITY
    Definition: type_nlhdlr.h:54
    unsigned int SCIP_NLHDLR_METHOD
    Definition: type_nlhdlr.h:57
    #define SCIP_DECL_NLHDLRDETECT(x)
    Definition: type_nlhdlr.h:177
    #define SCIP_NLHDLR_METHOD_NONE
    Definition: type_nlhdlr.h:50
    struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
    Definition: type_nlhdlr.h:453
    #define SCIP_NLHDLR_METHOD_ALL
    Definition: type_nlhdlr.h:55
    #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_FEASIBLE
    Definition: type_result.h:45
    @ 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
    @ SCIP_SOLVELP
    Definition: type_result.h:55
    @ SCIP_SUCCESS
    Definition: type_result.h:58
    @ SCIP_INFEASIBLE
    Definition: type_result.h:46
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_LPERROR
    Definition: type_retcode.h:49
    @ SCIP_READERROR
    Definition: type_retcode.h:45
    @ SCIP_INVALIDDATA
    Definition: type_retcode.h:52
    @ SCIP_PLUGINNOTFOUND
    Definition: type_retcode.h:54
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    @ SCIP_ERROR
    Definition: type_retcode.h:43
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_PROBLEM
    Definition: type_set.h:45
    @ SCIP_STAGE_INITPRESOLVE
    Definition: type_set.h:48
    @ SCIP_STAGE_SOLVED
    Definition: type_set.h:54
    @ SCIP_STAGE_PRESOLVING
    Definition: type_set.h:49
    @ SCIP_STAGE_TRANSFORMED
    Definition: type_set.h:47
    @ SCIP_STAGE_INITSOLVE
    Definition: type_set.h:52
    @ SCIP_STAGE_EXITPRESOLVE
    Definition: type_set.h:50
    @ SCIP_STAGE_EXITSOLVE
    Definition: type_set.h:55
    @ SCIP_STAGE_INIT
    Definition: type_set.h:44
    @ SCIP_STAGE_SOLVING
    Definition: type_set.h:53
    @ SCIP_SOLORIGIN_LPSOL
    Definition: type_sol.h:44
    @ SCIP_STATUS_OPTIMAL
    Definition: type_stat.h:43
    @ SCIP_STATUS_UNBOUNDED
    Definition: type_stat.h:45
    @ SCIP_STATUS_INFORUNBD
    Definition: type_stat.h:46
    @ SCIP_STATUS_INFEASIBLE
    Definition: type_stat.h:44
    enum SYM_Symtype SYM_SYMTYPE
    Definition: type_symmetry.h:64
    @ SYM_CONSOPTYPE_SUM
    Definition: type_symmetry.h:83
    @ SYM_CONSOPTYPE_COEF
    Definition: type_symmetry.h:85
    @ SYM_CONSOPTYPE_SQDIFF
    Definition: type_symmetry.h:86
    @ SYM_SYMTYPE_SIGNPERM
    Definition: type_symmetry.h:62
    @ SYM_SYMTYPE_PERM
    Definition: type_symmetry.h:61
    #define SCIP_PRESOLTIMING_ALWAYS
    Definition: type_timing.h:58
    #define SCIP_PRESOLTIMING_MEDIUM
    Definition: type_timing.h:53
    unsigned int SCIP_PRESOLTIMING
    Definition: type_timing.h:61
    #define SCIP_PRESOLTIMING_EXHAUSTIVE
    Definition: type_timing.h:54
    enum SCIP_ImplintType SCIP_IMPLINTTYPE
    Definition: type_var.h:117
    @ SCIP_IMPLINTTYPE_NONE
    Definition: type_var.h:90
    @ SCIP_IMPLINTTYPE_STRONG
    Definition: type_var.h:106
    @ SCIP_IMPLINTTYPE_WEAK
    Definition: type_var.h:91
    @ SCIP_VARTYPE_INTEGER
    Definition: type_var.h:65
    @ SCIP_VARTYPE_CONTINUOUS
    Definition: type_var.h:71
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64
    @ SCIP_VARSTATUS_COLUMN
    Definition: type_var.h:53
    @ SCIP_VARSTATUS_MULTAGGR
    Definition: type_var.h:56
    @ SCIP_LOCKTYPE_MODEL
    Definition: type_var.h:141