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 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    11099
    11100 /* create basic data of constraint handler and include it to scip */
    11102
    11103 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    11104 assert(targetconshdlr != NULL);
    11105 assert(targetconshdlr != conshdlr);
    11106
    11107 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
    11108 assert(sourceconshdlrdata != NULL);
    11109
    11110 /* copy nonlinear handlers */
    11111 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
    11112 {
    11113 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
    11114 }
    11115
    11116 *valid = TRUE;
    11117
    11118 return SCIP_OKAY;
    11119}
    11120
    11121/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
    11122static
    11123SCIP_DECL_CONSFREE(consFreeNonlinear)
    11124{ /*lint --e{715}*/
    11125 SCIP_CONSHDLRDATA* conshdlrdata;
    11126 int i;
    11127
    11128 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11129 assert(conshdlrdata != NULL);
    11130
    11131 /* free nonlinear handlers */
    11132 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11133 {
    11134 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
    11135 assert(conshdlrdata->nlhdlrs[i] == NULL);
    11136 }
    11137 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
    11138 conshdlrdata->nlhdlrssize = 0;
    11139
    11140 /* free upgrade functions */
    11141 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
    11142 {
    11143 assert(conshdlrdata->consupgrades[i] != NULL);
    11144 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
    11145 }
    11146 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
    11147
    11148 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
    11149
    11150 SCIPqueueFree(&conshdlrdata->reversepropqueue);
    11151
    11152 if( conshdlrdata->vp_randnumgen != NULL )
    11153 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
    11154
    11155 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
    11156 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
    11157 {
    11158 if( conshdlrdata->vp_lp[i] != NULL )
    11159 {
    11160 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
    11161 }
    11162 }
    11163
    11164 assert(conshdlrdata->branchrandnumgen == NULL);
    11165
    11166 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
    11167 SCIPhashmapFree(&conshdlrdata->var2expr);
    11168
    11169 SCIPfreeBlockMemory(scip, &conshdlrdata);
    11170 SCIPconshdlrSetData(conshdlr, NULL);
    11171
    11172 return SCIP_OKAY;
    11173}
    11174
    11175
    11176/** initialization method of constraint handler (called after problem was transformed) */
    11177static
    11178SCIP_DECL_CONSINIT(consInitNonlinear)
    11179{ /*lint --e{715}*/
    11180 SCIP_CONSHDLRDATA* conshdlrdata;
    11181 int i;
    11182
    11183 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11184 assert(conshdlrdata != NULL);
    11185
    11186 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
    11187 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
    11188 /* set to 1 so it is larger than initial value of lastenforound in exprs */
    11189 conshdlrdata->enforound = 1;
    11190 /* reset numbering for auxiliary variables */
    11191 conshdlrdata->auxvarid = 0;
    11192
    11193 for( i = 0; i < nconss; ++i )
    11194 {
    11195 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
    11196 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
    11197 }
    11198
    11199 /* sort nonlinear handlers by detection priority, in decreasing order */
    11200 if( conshdlrdata->nnlhdlrs > 1 )
    11201 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
    11202
    11203 /* get heuristics for later use */
    11204 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
    11205 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
    11206
    11207 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
    11208 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11209 {
    11210 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
    11211 }
    11212
    11213 /* reset statistics in constraint handler */
    11214 conshdlrdata->nweaksepa = 0;
    11215 conshdlrdata->ntightenlp = 0;
    11216 conshdlrdata->ndesperatebranch = 0;
    11217 conshdlrdata->ndesperatecutoff = 0;
    11218 conshdlrdata->ndesperatetightenlp = 0;
    11219 conshdlrdata->nforcelp = 0;
    11220 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
    11221 conshdlrdata->ncanonicalizecalls = 0;
    11222
    11223#ifdef ENFOLOGFILE
    11224 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
    11225#endif
    11226
    11227 return SCIP_OKAY;
    11228}
    11229
    11230
    11231/** deinitialization method of constraint handler (called before transformed problem is freed) */
    11232static
    11233SCIP_DECL_CONSEXIT(consExitNonlinear)
    11234{ /*lint --e{715}*/
    11235 SCIP_CONSHDLRDATA* conshdlrdata;
    11236 SCIP_CONS** consssorted;
    11237 int i;
    11238
    11239 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11240 assert(conshdlrdata != NULL);
    11241
    11242 if( nconss > 0 )
    11243 {
    11244 /* for better performance of dropVarEvents, we sort by index, descending */
    11245 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
    11246 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
    11247
    11248 for( i = 0; i < nconss; ++i )
    11249 {
    11250 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
    11251 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
    11252 }
    11253
    11254 SCIPfreeBufferArray(scip, &consssorted);
    11255 }
    11256
    11257 conshdlrdata->subnlpheur = NULL;
    11258 conshdlrdata->trysolheur = NULL;
    11259
    11260 if( conshdlrdata->vp_randnumgen != NULL )
    11261 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
    11262
    11263 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
    11264 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
    11265 {
    11266 if( conshdlrdata->vp_lp[i] != NULL )
    11267 {
    11268 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
    11269 }
    11270 }
    11271
    11272 if( conshdlrdata->branchrandnumgen != NULL )
    11273 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
    11274
    11275 /* deinitialize nonlinear handlers */
    11276 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11277 {
    11278 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
    11279 }
    11280
    11281 ENFOLOG(
    11282 if( enfologfile != NULL )
    11283 {
    11284 fclose(enfologfile);
    11285 enfologfile = NULL;
    11286 })
    11287
    11288 return SCIP_OKAY;
    11289}
    11290
    11291
    11292/** presolving initialization method of constraint handler (called when presolving is about to begin) */
    11293#ifdef SCIP_DISABLED_CODE
    11294static
    11296{ /*lint --e{715}*/
    11297 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    11298 SCIPABORT(); /*lint --e{527}*/
    11299
    11300 return SCIP_OKAY;
    11301}
    11302#else
    11303#define consInitpreNonlinear NULL
    11304#endif
    11305
    11306
    11307/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
    11308static
    11309SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
    11310{ /*lint --e{715}*/
    11311 SCIP_Bool infeasible;
    11312
    11313 if( nconss == 0 )
    11314 return SCIP_OKAY;
    11315
    11316 /* skip some extra work if already known to be infeasible */
    11318 return SCIP_OKAY;
    11319
    11320 /* simplify constraints and replace common subexpressions */
    11321 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
    11322
    11323 /* currently SCIP does not offer to communicate this,
    11324 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
    11325 * or if a constraint expression became constant
    11326 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
    11327 */
    11328 /* assert(!infeasible); */
    11329
    11330 /* tell SCIP that we have something nonlinear */
    11332
    11333 return SCIP_OKAY;
    11334}
    11335
    11336
    11337/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
    11338static
    11339SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
    11340{ /*lint --e{715}*/
    11341 SCIP_CONSHDLRDATA* conshdlrdata;
    11342 int i;
    11343
    11344 /* skip remaining initializations if we have solved already
    11345 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
    11346 * assumes nonempty activities in expressions
    11347 */
    11348 switch( SCIPgetStatus(scip) )
    11349 {
    11354 return SCIP_OKAY;
    11355 default: ;
    11356 } /*lint !e788 */
    11357
    11358 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11359 assert(conshdlrdata != NULL);
    11360
    11361 /* reset one of the number of detections counter to count only current round */
    11362 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11363 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
    11364
    11365 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
    11366
    11367 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
    11368 if( conshdlrdata->branchpscostweight > 0.0 )
    11369 {
    11370 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
    11371 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
    11372 {
    11373 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
    11374 SCIPABORT();
    11375 return SCIP_INVALIDDATA;
    11376 }
    11377 }
    11378
    11379 return SCIP_OKAY;
    11380}
    11381
    11382
    11383/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    11384static
    11385SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
    11386{ /*lint --e{715}*/
    11387 SCIP_CONSHDLRDATA* conshdlrdata;
    11388
    11389 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
    11390
    11391 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11392 assert(conshdlrdata != NULL);
    11393
    11394 /* free hash table for bilinear terms */
    11395 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
    11396
    11397 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
    11398 conshdlrdata->checkedvarlocks = FALSE;
    11399
    11400 /* drop catching new solution event, if catched before */
    11401 if( conshdlrdata->newsoleventfilterpos >= 0 )
    11402 {
    11403 SCIP_EVENTHDLR* eventhdlr;
    11404
    11405 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
    11406 assert(eventhdlr != NULL);
    11407
    11408 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
    11409 conshdlrdata->newsoleventfilterpos = -1;
    11410 }
    11411
    11412 return SCIP_OKAY;
    11413}
    11414
    11415
    11416/** frees specific constraint data */
    11417static
    11418SCIP_DECL_CONSDELETE(consDeleteNonlinear)
    11419{ /*lint --e{715}*/
    11420 assert(consdata != NULL);
    11421 assert(*consdata != NULL);
    11422 assert((*consdata)->expr != NULL);
    11423
    11424 /* constraint locks should have been removed */
    11425 assert((*consdata)->nlockspos == 0);
    11426 assert((*consdata)->nlocksneg == 0);
    11427
    11428 /* free variable expressions */
    11429 SCIP_CALL( freeVarExprs(scip, *consdata) );
    11430
    11431 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
    11432
    11433 /* free nonlinear row representation */
    11434 if( (*consdata)->nlrow != NULL )
    11435 {
    11436 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
    11437 }
    11438
    11439 SCIPfreeBlockMemory(scip, consdata);
    11440
    11441 return SCIP_OKAY;
    11442}
    11443
    11444
    11445/** transforms constraint data into data belonging to the transformed problem */
    11446static
    11447SCIP_DECL_CONSTRANS(consTransNonlinear)
    11448{ /*lint --e{715}*/
    11449 SCIP_EXPR* targetexpr;
    11450 SCIP_CONSDATA* sourcedata;
    11451
    11452 sourcedata = SCIPconsGetData(sourcecons);
    11453 assert(sourcedata != NULL);
    11454
    11455 /* get a copy of sourceexpr with transformed vars */
    11456 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    11457 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
    11458
    11459 /* create transformed cons (only captures targetexpr, no need to copy again) */
    11460 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
    11461 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
    11462 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
    11463 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
    11464 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
    11465 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
    11466
    11467 /* release target expr */
    11468 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
    11469
    11470 return SCIP_OKAY;
    11471}
    11472
    11473
    11474/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
    11475static
    11476SCIP_DECL_CONSINITLP(consInitlpNonlinear)
    11477{ /*lint --e{715}*/
    11478 SCIP_CONSHDLRDATA* conshdlrdata;
    11479
    11480 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
    11481 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
    11482 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
    11483 * for now, there is an assert in detectNlhdlrs to require initial if separated
    11484 */
    11485 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
    11486
    11487 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11488 assert(conshdlrdata != NULL);
    11489
    11490 /* catch new solution event */
    11491 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
    11492 {
    11493 SCIP_EVENTHDLR* eventhdlr;
    11494
    11495 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
    11496 assert(eventhdlr != NULL);
    11497
    11498 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
    11499 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
    11500 }
    11501
    11502 /* collect all bilinear terms for which an auxvar is present
    11503 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
    11504 * addition (and removal?) of constraints during solve
    11505 * this is typically the majority of constraints, but the method should be made more flexible
    11506 */
    11507 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
    11508
    11509 return SCIP_OKAY;
    11510}
    11511
    11512
    11513/** separation method of constraint handler for LP solutions */
    11514static
    11515SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
    11516{ /*lint --e{715}*/
    11517 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
    11518
    11519 return SCIP_OKAY;
    11520}
    11521
    11522
    11523/** separation method of constraint handler for arbitrary primal solutions */
    11524static
    11525SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
    11526{ /*lint --e{715}*/
    11527 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
    11528
    11529 return SCIP_OKAY;
    11530}
    11531
    11532
    11533/** constraint enforcing method of constraint handler for LP solutions */
    11534static
    11535SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
    11536{ /*lint --e{715}*/
    11537 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
    11538
    11539 return SCIP_OKAY;
    11540}
    11541
    11542
    11543/** constraint enforcing method of constraint handler for relaxation solutions */
    11544static
    11545SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
    11546{ /*lint --e{715}*/
    11547 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
    11548
    11549 return SCIP_OKAY;
    11550}
    11551
    11552
    11553/** constraint enforcing method of constraint handler for pseudo solutions */
    11554static
    11555SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
    11556{ /*lint --e{715}*/
    11557 SCIP_RESULT propresult;
    11558 SCIP_Longint soltag;
    11559 int nchgbds;
    11560 int nnotify;
    11561 int c;
    11562
    11563 soltag = SCIPgetExprNewSoltag(scip);
    11564
    11565 *result = SCIP_FEASIBLE;
    11566 for( c = 0; c < nconss; ++c )
    11567 {
    11568 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
    11569
    11570 if( isConsViolated(scip, conss[c]) )
    11571 *result = SCIP_INFEASIBLE;
    11572 }
    11573
    11574 if( *result == SCIP_FEASIBLE )
    11575 return SCIP_OKAY;
    11576
    11577 /* try to propagate
    11578 * TODO obey propinenfo parameter, but we need something to recognize cutoff
    11579 */
    11580 nchgbds = 0;
    11581 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
    11582
    11583 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
    11584 {
    11585 *result = propresult;
    11586 return SCIP_OKAY;
    11587 }
    11588
    11589 /* register all unfixed variables in all violated constraints as branching candidates */
    11590 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
    11591 if( nnotify > 0 )
    11592 {
    11593 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
    11594
    11595 return SCIP_OKAY;
    11596 }
    11597
    11598 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
    11599 *result = SCIP_SOLVELP;
    11600 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
    11601
    11602 return SCIP_OKAY;
    11603}
    11604
    11605
    11606/** feasibility check method of constraint handler for integral solutions */
    11607static
    11608SCIP_DECL_CONSCHECK(consCheckNonlinear)
    11609{ /*lint --e{715}*/
    11610 SCIP_CONSHDLRDATA* conshdlrdata;
    11611 SCIP_CONSDATA* consdata;
    11612 SCIP_Real maxviol;
    11613 SCIP_Bool maypropfeasible;
    11614 SCIP_Longint soltag;
    11615 int c;
    11616
    11617 assert(scip != NULL);
    11618 assert(conshdlr != NULL);
    11619 assert(conss != NULL || nconss == 0);
    11620 assert(result != NULL);
    11621
    11622 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11623 assert(conshdlrdata != NULL);
    11624
    11625 *result = SCIP_FEASIBLE;
    11626 soltag = SCIPgetExprNewSoltag(scip);
    11627 maxviol = 0.0;
    11628 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
    11630
    11631 if( maypropfeasible && (sol == NULL || SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_LPSOL) && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
    11632 maypropfeasible = FALSE;
    11633
    11634 /* check nonlinear constraints for feasibility */
    11635 for( c = 0; c < nconss; ++c )
    11636 {
    11637 SCIP_Real absviol;
    11638 SCIP_Real relviol;
    11639
    11640 assert(conss != NULL && conss[c] != NULL);
    11641 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
    11642
    11643 absviol = getConsAbsViolation(conss[c]);
    11644 SCIP_CALL( getConsRelViolation(scip, conss[c], &relviol, sol, soltag) );
    11645 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
    11646
    11647 if( absviol > SCIPfeastol(scip) )
    11648 {
    11649 *result = SCIP_INFEASIBLE;
    11650 maxviol = MAX(maxviol, absviol);
    11651
    11652 consdata = SCIPconsGetData(conss[c]);
    11653 assert(consdata != NULL);
    11654
    11655 /* print reason for infeasibility */
    11656 if( printreason )
    11657 {
    11658 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
    11659 SCIPinfoMessage(scip, NULL, ";\n");
    11660
    11661 if( consdata->lhsviol > SCIPfeastol(scip) )
    11662 {
    11663 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
    11664 }
    11665 if( consdata->rhsviol > SCIPfeastol(scip) )
    11666 {
    11667 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
    11668 }
    11669 }
    11670 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
    11671 {
    11672 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
    11673 return SCIP_OKAY;
    11674 }
    11675
    11676 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
    11677 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
    11678 maypropfeasible = FALSE;
    11679
    11680 if( maypropfeasible )
    11681 {
    11682 if( consdata->lhsviol > SCIPfeastol(scip) )
    11683 {
    11684 /* check if there is a variable which may help to get the left hand side satisfied
    11685 * if there is no such variable, then we cannot get feasible
    11686 */
    11687 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
    11688 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
    11689 maypropfeasible = FALSE;
    11690 }
    11691 else
    11692 {
    11693 assert(consdata->rhsviol > SCIPfeastol(scip));
    11694 /* check if there is a variable which may help to get the right hand side satisfied
    11695 * if there is no such variable, then we cannot get feasible
    11696 */
    11697 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
    11698 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
    11699 maypropfeasible = FALSE;
    11700 }
    11701 }
    11702 }
    11703 }
    11704
    11705 if( *result == SCIP_INFEASIBLE && maypropfeasible )
    11706 {
    11707 SCIP_Bool success;
    11708
    11709 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
    11710
    11711 /* do not pass solution to NLP heuristic if we made it feasible this way */
    11712 if( success )
    11713 return SCIP_OKAY;
    11714 }
    11715
    11716 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
    11717 {
    11718 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
    11719 }
    11720
    11721 return SCIP_OKAY;
    11722}
    11723
    11724
    11725/** domain propagation method of constraint handler */
    11726static
    11727SCIP_DECL_CONSPROP(consPropNonlinear)
    11728{ /*lint --e{715}*/
    11729 int nchgbds = 0;
    11730
    11731 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
    11732 assert(nchgbds >= 0);
    11733
    11734 /* TODO would it make sense to check for redundant constraints? */
    11735
    11736 return SCIP_OKAY;
    11737}
    11738
    11739
    11740/** presolving method of constraint handler */
    11741static
    11742SCIP_DECL_CONSPRESOL(consPresolNonlinear)
    11743{ /*lint --e{715}*/
    11744 SCIP_CONSHDLRDATA* conshdlrdata;
    11745 SCIP_Bool infeasible;
    11746 int c;
    11747
    11748 *result = SCIP_DIDNOTFIND;
    11749
    11750 if( nconss == 0 )
    11751 {
    11752 *result = SCIP_DIDNOTRUN;
    11753 return SCIP_OKAY;
    11754 }
    11755
    11756 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11757 assert(conshdlrdata != NULL);
    11758
    11759 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
    11760 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
    11761 if( infeasible )
    11762 {
    11763 *result = SCIP_CUTOFF;
    11764 return SCIP_OKAY;
    11765 }
    11766
    11767 /* merge constraints with the same root expression */
    11768 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
    11769 {
    11770 SCIP_Bool success;
    11771
    11772 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
    11773 if( success )
    11774 *result = SCIP_SUCCESS;
    11775 }
    11776
    11777 /* propagate constraints */
    11778 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
    11779 if( *result == SCIP_CUTOFF )
    11780 return SCIP_OKAY;
    11781
    11782 /* propagate function domains (TODO integrate with simplify?) */
    11783 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
    11784 {
    11785 SCIP_RESULT localresult;
    11786 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
    11787 if( localresult == SCIP_CUTOFF )
    11788 {
    11789 *result = SCIP_CUTOFF;
    11790 return SCIP_OKAY;
    11791 }
    11792 if( localresult == SCIP_REDUCEDDOM )
    11793 *result = SCIP_REDUCEDDOM;
    11794 }
    11795
    11796 /* check for redundant constraints, remove constraints that are a value expression */
    11797 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
    11798 if( infeasible )
    11799 {
    11800 *result = SCIP_CUTOFF;
    11801 return SCIP_OKAY;
    11802 }
    11803
    11804 /* try to upgrade constraints */
    11805 for( c = 0; c < nconss; ++c )
    11806 {
    11807 SCIP_Bool upgraded;
    11808
    11809 /* skip inactive and deleted constraints */
    11810 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
    11811 continue;
    11812
    11813 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
    11814 }
    11815
    11816 /* try to change continuous variables that appear linearly to be implicit integer */
    11817 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
    11818 {
    11819 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
    11820
    11821 if( infeasible )
    11822 {
    11823 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
    11824 *result = SCIP_CUTOFF;
    11825 return SCIP_OKAY;
    11826 }
    11827 }
    11828
    11829 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
    11831 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
    11832 {
    11833 /* run this presolving technique only once because we don't want to generate identical bound disjunction
    11834 * constraints multiple times
    11835 */
    11836 conshdlrdata->checkedvarlocks = TRUE;
    11837
    11838 for( c = 0; c < nconss; ++c )
    11839 {
    11840 int tmpnchgvartypes = 0;
    11841 int tmpnaddconss = 0;
    11842
    11843 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
    11844 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
    11845 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
    11846
    11847 if( infeasible )
    11848 {
    11849 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
    11850 *result = SCIP_CUTOFF;
    11851 return SCIP_OKAY;
    11852 }
    11853
    11854 (*nchgvartypes) += tmpnchgvartypes;
    11855 (*naddconss) += tmpnaddconss;
    11856 }
    11857 }
    11858
    11859 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
    11860 *result = SCIP_SUCCESS;
    11861 else
    11862 *result = SCIP_DIDNOTFIND;
    11863
    11864 return SCIP_OKAY;
    11865}
    11866
    11867
    11868/** propagation conflict resolving method of constraint handler */
    11869#ifdef SCIP_DISABLED_CODE
    11870static
    11872{ /*lint --e{715}*/
    11873 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    11874 SCIPABORT(); /*lint --e{527}*/
    11875
    11876 return SCIP_OKAY;
    11877}
    11878#else
    11879#define consRespropNonlinear NULL
    11880#endif
    11881
    11882
    11883/** variable rounding lock method of constraint handler */
    11884static
    11885SCIP_DECL_CONSLOCK(consLockNonlinear)
    11886{ /*lint --e{715}*/
    11887 SCIP_CONSDATA* consdata;
    11888 SCIP_EXPR_OWNERDATA* ownerdata;
    11889 SCIP_Bool reinitsolve = FALSE;
    11890
    11891 assert(conshdlr != NULL);
    11892 assert(cons != NULL);
    11893
    11894 consdata = SCIPconsGetData(cons);
    11895 assert(consdata != NULL);
    11896 assert(consdata->expr != NULL);
    11897
    11898 ownerdata = SCIPexprGetOwnerData(consdata->expr);
    11899
    11900 /* check whether we need to initSolve again because
    11901 * - we have enfo initialized (nenfos >= 0)
    11902 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
    11903 */
    11904 if( ownerdata->nenfos >= 0 )
    11905 {
    11906 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
    11907 reinitsolve = TRUE;
    11908 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
    11909 reinitsolve = TRUE;
    11910 }
    11911
    11912 if( reinitsolve )
    11913 {
    11914 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
    11915 }
    11916
    11917 /* add locks */
    11918 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
    11919
    11920 if( reinitsolve )
    11921 {
    11922 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
    11923 }
    11924
    11925 return SCIP_OKAY;
    11926}
    11927
    11928
    11929/** constraint activation notification method of constraint handler */
    11930static
    11931SCIP_DECL_CONSACTIVE(consActiveNonlinear)
    11932{ /*lint --e{715}*/
    11933 SCIP_CONSDATA* consdata;
    11934 SCIP_Bool infeasible = FALSE;
    11935
    11936 consdata = SCIPconsGetData(cons);
    11937 assert(consdata != NULL);
    11938
    11939 /* simplify root expression if the constraint has been added after presolving */
    11941 {
    11942 SCIP_Bool replacedroot;
    11943
    11944 if( !consdata->issimplified )
    11945 {
    11946 SCIP_EXPR* simplified;
    11947 SCIP_Bool changed;
    11948
    11949 /* simplify constraint */
    11950 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
    11951 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    11952 assert(simplified != NULL);
    11953 consdata->expr = simplified;
    11954 consdata->issimplified = TRUE;
    11955 }
    11956
    11957 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
    11958 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
    11959 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
    11960
    11961 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
    11962 {
    11963 SCIP_CONSHDLRDATA* conshdlrdata;
    11964 SCIP_EXPRITER* it;
    11965 SCIP_EXPR* expr;
    11966
    11967 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11968 assert(conshdlrdata != NULL);
    11969
    11971 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
    11973 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    11974 {
    11975 SCIP_EXPR* child;
    11976 SCIP_EXPR* hashmapexpr;
    11977
    11978 child = SCIPexpriterGetChildExprDFS(it);
    11979 if( !SCIPisExprVar(scip, child) )
    11980 continue;
    11981
    11982 /* check which expression is stored in the hashmap for the var of child */
    11983 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
    11984 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
    11985 if( hashmapexpr != NULL && hashmapexpr != child )
    11986 {
    11988 }
    11989 }
    11990 SCIPfreeExpriter(&it);
    11991 }
    11992 }
    11993
    11994 /* store variable expressions */
    11996 {
    11997 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    11998 }
    11999
    12000 /* add manually locks to constraints that are not checked for feasibility */
    12001 if( !SCIPconsIsChecked(cons) )
    12002 {
    12003 assert(consdata->nlockspos == 0);
    12004 assert(consdata->nlocksneg == 0);
    12005
    12006 SCIP_CALL( addLocks(scip, cons, 1, 0) );
    12007 }
    12008
    12009 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
    12010 {
    12011 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
    12012 }
    12013
    12014 /* TODO deal with infeasibility */
    12015 assert(!infeasible);
    12016
    12017 return SCIP_OKAY;
    12018}
    12019
    12020
    12021/** constraint deactivation notification method of constraint handler */
    12022static
    12023SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
    12024{ /*lint --e{715}*/
    12025 SCIP_CONSHDLRDATA* conshdlrdata;
    12026
    12027 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12028 assert(conshdlrdata != NULL);
    12029
    12031 {
    12032 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
    12033 }
    12034
    12036 {
    12037 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
    12039 }
    12040
    12041 /* remove locks that have been added in consActiveExpr() */
    12042 if( !SCIPconsIsChecked(cons) )
    12043 {
    12044 SCIP_CALL( addLocks(scip, cons, -1, 0) );
    12045
    12046 assert(SCIPconsGetData(cons)->nlockspos == 0);
    12047 assert(SCIPconsGetData(cons)->nlocksneg == 0);
    12048 }
    12049
    12050 return SCIP_OKAY;
    12051}
    12052
    12053
    12054/** constraint enabling notification method of constraint handler */
    12055static
    12056SCIP_DECL_CONSENABLE(consEnableNonlinear)
    12057{ /*lint --e{715}*/
    12058 SCIP_CONSHDLRDATA* conshdlrdata;
    12059
    12060 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12061 assert(conshdlrdata != NULL);
    12062
    12064 {
    12065 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
    12066 }
    12067
    12068 return SCIP_OKAY;
    12069}
    12070
    12071
    12072/** constraint disabling notification method of constraint handler */
    12073static
    12074SCIP_DECL_CONSDISABLE(consDisableNonlinear)
    12075{ /*lint --e{715}*/
    12076 SCIP_CONSHDLRDATA* conshdlrdata;
    12077
    12078 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12079 assert(conshdlrdata != NULL);
    12080
    12082 {
    12083 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
    12084 }
    12085
    12086 return SCIP_OKAY;
    12087}
    12088
    12089/** variable deletion of constraint handler */
    12090#ifdef SCIP_DISABLED_CODE
    12091static
    12093{ /*lint --e{715}*/
    12094 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    12095 SCIPABORT(); /*lint --e{527}*/
    12096
    12097 return SCIP_OKAY;
    12098}
    12099#else
    12100#define consDelvarsNonlinear NULL
    12101#endif
    12102
    12103
    12104/** constraint display method of constraint handler */
    12105static
    12106SCIP_DECL_CONSPRINT(consPrintNonlinear)
    12107{ /*lint --e{715}*/
    12108 SCIP_CONSDATA* consdata;
    12109
    12110 consdata = SCIPconsGetData(cons);
    12111 assert(consdata != NULL);
    12112 assert(consdata->expr != NULL);
    12113
    12114 /* print left hand side for ranged constraints */
    12115 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
    12116 {
    12117 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
    12118 }
    12119
    12120 /* print expression */
    12121 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
    12122
    12123 /* print right hand side */
    12124 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
    12125 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
    12126 else if( !SCIPisInfinity(scip, consdata->rhs) )
    12127 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
    12128 else if( !SCIPisInfinity(scip, -consdata->lhs) )
    12129 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
    12130 else
    12131 SCIPinfoMessage(scip, file, " [free]");
    12132
    12133 return SCIP_OKAY;
    12134}
    12135
    12136
    12137/** constraint copying method of constraint handler */
    12138static
    12139SCIP_DECL_CONSCOPY(consCopyNonlinear)
    12140{ /*lint --e{715}*/
    12141 SCIP_CONSHDLR* targetconshdlr;
    12142 SCIP_EXPR* targetexpr = NULL;
    12143 SCIP_CONSDATA* sourcedata;
    12144
    12145 assert(cons != NULL);
    12146
    12147 sourcedata = SCIPconsGetData(sourcecons);
    12148 assert(sourcedata != NULL);
    12149
    12150 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12151 assert(targetconshdlr != NULL);
    12152
    12153 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
    12154
    12155 if( targetexpr == NULL )
    12156 *valid = FALSE;
    12157
    12158 *cons = NULL;
    12159 if( *valid )
    12160 {
    12161 /* create copy (only capture targetexpr, no need to copy again) */
    12162 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
    12163 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
    12164 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12165 }
    12166
    12167 if( targetexpr != NULL )
    12168 {
    12169 /* release target expr */
    12170 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
    12171 }
    12172
    12173 return SCIP_OKAY;
    12174}
    12175
    12176
    12177/** constraint parsing method of constraint handler */
    12178static
    12179SCIP_DECL_CONSPARSE(consParseNonlinear)
    12180{ /*lint --e{715}*/
    12181 SCIP_Real lhs;
    12182 SCIP_Real rhs;
    12183 char* endptr;
    12184 SCIP_EXPR* consexprtree;
    12185
    12186 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
    12187
    12188 assert(scip != NULL);
    12189 assert(success != NULL);
    12190 assert(str != NULL);
    12191 assert(name != NULL);
    12192 assert(cons != NULL);
    12193
    12194 *success = FALSE;
    12195
    12196 /* return if string empty */
    12197 if( !*str )
    12198 return SCIP_OKAY;
    12199
    12200 endptr = (char*)str;
    12201
    12202 /* set left and right hand side to their default values */
    12203 lhs = -SCIPinfinity(scip);
    12204 rhs = SCIPinfinity(scip);
    12205
    12206 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
    12207
    12208 /* check for left hand side */
    12209 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
    12210 {
    12211 /* there is a number coming, maybe it is a left-hand-side */
    12212 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
    12213 {
    12214 SCIPerrorMessage("error parsing number from <%s>\n", str);
    12215 return SCIP_READERROR;
    12216 }
    12217
    12218 /* ignore whitespace */
    12219 SCIP_CALL( SCIPskipSpace(&endptr) );
    12220
    12221 if( endptr[0] != '<' || endptr[1] != '=' )
    12222 {
    12223 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
    12224 lhs = -SCIPinfinity(scip);
    12225 }
    12226 else
    12227 {
    12228 /* it was indeed a left-hand-side, so continue parsing after it */
    12229 str = endptr + 2;
    12230
    12231 /* ignore whitespace */
    12232 SCIP_CALL( SCIPskipSpace((char**)&str) );
    12233 }
    12234 }
    12235
    12236 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
    12237
    12238 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
    12239 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
    12240
    12241 /* check for left or right hand side */
    12242 SCIP_CALL( SCIPskipSpace((char**)&str) );
    12243
    12244 /* check for free constraint */
    12245 if( strncmp(str, "[free]", 6) == 0 )
    12246 {
    12247 if( !SCIPisInfinity(scip, -lhs) )
    12248 {
    12249 SCIPerrorMessage("cannot have left hand side and [free] status \n");
    12250 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12251 return SCIP_OKAY;
    12252 }
    12253 *success = TRUE;
    12254 }
    12255 else
    12256 {
    12257 switch( *str )
    12258 {
    12259 case '<':
    12260 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
    12261 break;
    12262 case '=':
    12263 if( !SCIPisInfinity(scip, -lhs) )
    12264 {
    12265 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
    12266 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12267 return SCIP_OKAY;
    12268 }
    12269 else
    12270 {
    12271 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
    12272 lhs = rhs;
    12273 }
    12274 break;
    12275 case '>':
    12276 if( !SCIPisInfinity(scip, -lhs) )
    12277 {
    12278 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
    12279 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12280 return SCIP_OKAY;
    12281 }
    12282 else
    12283 {
    12284 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
    12285 break;
    12286 }
    12287 case '\0':
    12288 *success = TRUE;
    12289 break;
    12290 default:
    12291 SCIPerrorMessage("unexpected character %c\n", *str);
    12292 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12293 return SCIP_OKAY;
    12294 }
    12295 }
    12296
    12297 /* create constraint */
    12298 SCIP_CALL( createCons(scip, conshdlr, cons, name,
    12299 consexprtree, lhs, rhs, FALSE,
    12300 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12301 assert(*cons != NULL);
    12302
    12303 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12304
    12305 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
    12306
    12307 return SCIP_OKAY;
    12308}
    12309
    12310
    12311/** constraint method of constraint handler which returns the variables (if possible) */
    12312static
    12313SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
    12314{ /*lint --e{715}*/
    12315 SCIP_CONSDATA* consdata;
    12316 int i;
    12317
    12318 consdata = SCIPconsGetData(cons);
    12319 assert(consdata != NULL);
    12320
    12321 /* store variable expressions if not done so far */
    12322 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    12323
    12324 /* check whether array is too small in order to store all variables */
    12325 if( varssize < consdata->nvarexprs )
    12326 {
    12327 *success = FALSE;
    12328 return SCIP_OKAY;
    12329 }
    12330
    12331 for( i = 0; i < consdata->nvarexprs; ++i )
    12332 {
    12333 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
    12334 assert(vars[i] != NULL);
    12335 }
    12336
    12337 *success = TRUE;
    12338
    12339 return SCIP_OKAY;
    12340}
    12341
    12342/** constraint method of constraint handler which returns the number of variables (if possible) */
    12343static
    12344SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
    12345{ /*lint --e{715}*/
    12346 SCIP_CONSDATA* consdata;
    12347
    12348 consdata = SCIPconsGetData(cons);
    12349 assert(consdata != NULL);
    12350
    12351 /* store variable expressions if not done so far */
    12352 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    12353
    12354 *nvars = consdata->nvarexprs;
    12355 *success = TRUE;
    12356
    12357 return SCIP_OKAY;
    12358}
    12359
    12360/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
    12361#ifdef SCIP_DISABLED_CODE
    12362static
    12364{ /*lint --e{715}*/
    12365 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    12366 SCIPABORT(); /*lint --e{527}*/
    12367
    12368 return SCIP_OKAY;
    12369}
    12370#else
    12371#define consGetDiveBdChgsNonlinear NULL
    12372#endif
    12373
    12374/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
    12375static
    12376SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
    12377{ /*lint --e{715}*/
    12378 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
    12379
    12380 return SCIP_OKAY;
    12381}
    12382
    12383/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
    12384static
    12385SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
    12386{ /*lint --e{715}*/
    12387 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
    12388
    12389 return SCIP_OKAY;
    12390}
    12391
    12392/** output method of cons_nonlinear statistics table to output file stream 'file' */
    12393static
    12394SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
    12395{ /*lint --e{715}*/
    12396 SCIP_CONSHDLR* conshdlr;
    12397 SCIP_CONSHDLRDATA* conshdlrdata;
    12398
    12399 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12400 assert(conshdlr != NULL);
    12401
    12402 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12403 assert(conshdlrdata != NULL);
    12404
    12405 /* print statistics for constraint handler */
    12406 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
    12407 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
    12408 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
    12409 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
    12410 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
    12411 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
    12412 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
    12413 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
    12414 SCIPinfoMessage(scip, file, "\n");
    12415 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
    12416 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
    12417 SCIPinfoMessage(scip, file, "\n");
    12418
    12419 return SCIP_OKAY;
    12420}
    12421
    12422/** collect method of cons_nonlinear statistics table to SCIP_DATATREE */
    12423static
    12424SCIP_DECL_TABLECOLLECT(tableCollectNonlinear)
    12425{
    12426 SCIP_CONSHDLR* conshdlr;
    12427 SCIP_CONSHDLRDATA* conshdlrdata;
    12428
    12429 assert(scip != NULL);
    12430 assert(table != NULL);
    12431 assert(datatree != NULL);
    12432
    12433 /* Find the constraint handler */
    12434 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12435 assert(conshdlr != NULL);
    12436
    12437 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12438 assert(conshdlrdata != NULL);
    12439
    12440 /* Insert statistics */
    12441 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nweakseparation", conshdlrdata->nweaksepa) );
    12442 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ntightenlp", conshdlrdata->ntightenlp) );
    12443 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatetightenlp", conshdlrdata->ndesperatetightenlp) );
    12444 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatebranch", conshdlrdata->ndesperatebranch) );
    12445 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatecutoff", conshdlrdata->ndesperatecutoff) );
    12446 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nforcelp", conshdlrdata->nforcelp) );
    12447 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "canonicalizationtime", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime)) );
    12448
    12449 return SCIP_OKAY;
    12450}
    12451
    12452/** output method of nlhdlr statistics table to output file stream 'file' */
    12453static
    12454SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
    12455{ /*lint --e{715}*/
    12456 SCIP_CONSHDLR* conshdlr;
    12457 SCIP_CONSHDLRDATA* conshdlrdata;
    12458
    12459 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12460 assert(conshdlr != NULL);
    12461
    12462 /* skip nlhdlr table if there never were active nonlinear constraints */
    12463 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
    12464 return SCIP_OKAY;
    12465
    12466 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12467 assert(conshdlrdata != NULL);
    12468
    12469 /* print statistics for nonlinear handlers */
    12470 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
    12471
    12472 return SCIP_OKAY;
    12473}
    12474
    12475/** collect method of nlhdlr statistics table to SCIP_DATATREE */
    12476static
    12477SCIP_DECL_TABLECOLLECT(tableCollectNlhdlr)
    12478{ /*lint --e{715}*/
    12479 SCIP_CONSHDLR* conshdlr;
    12480 SCIP_CONSHDLRDATA* conshdlrdata;
    12481
    12482 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12483 assert(conshdlr != NULL);
    12484
    12485 /* skip nlhdlr table if there never were active nonlinear constraints */
    12486 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
    12487 return SCIP_OKAY;
    12488
    12489 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12490 assert(conshdlrdata != NULL);
    12491
    12492 /* collect statistics for nonlinear handlers */
    12493 SCIP_CALL( SCIPnlhdlrCollectStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, datatree) );
    12494
    12495 return SCIP_OKAY;
    12496}
    12497
    12498/** execution method of display nlhdlrs dialog */
    12499static
    12500SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
    12501{ /*lint --e{715}*/
    12502 SCIP_CONSHDLR* conshdlr;
    12503 SCIP_CONSHDLRDATA* conshdlrdata;
    12504 int i;
    12505
    12506 /* add dialog to history of dialogs that have been executed */
    12507 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
    12508
    12509 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12510 assert(conshdlr != NULL);
    12511
    12512 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12513 assert(conshdlrdata != NULL);
    12514
    12515 /* display list of nonlinear handler */
    12516 SCIPdialogMessage(scip, NULL, "\n");
    12517 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
    12518 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
    12519 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    12520 {
    12521 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
    12522 assert(nlhdlr != NULL);
    12523
    12524 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
    12525 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
    12528 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
    12529 SCIPdialogMessage(scip, NULL, "\n");
    12530 }
    12531 SCIPdialogMessage(scip, NULL, "\n");
    12532
    12533 /* next dialog will be root dialog again */
    12534 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
    12535
    12536 return SCIP_OKAY;
    12537}
    12538
    12539/*
    12540 * constraint handler specific interface methods
    12541 */
    12542
    12543/** creates the handler for nonlinear constraints and includes it in SCIP */
    12545 SCIP* scip /**< SCIP data structure */
    12546 )
    12547{
    12548 SCIP_CONSHDLRDATA* conshdlrdata;
    12549 SCIP_DIALOG* parentdialog;
    12550
    12551 /* create nonlinear constraint handler data */
    12552 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
    12553 conshdlrdata->intevalvar = intEvalVarBoundTightening;
    12554 conshdlrdata->curboundstag = 1;
    12555 conshdlrdata->lastboundrelax = 1;
    12556 conshdlrdata->curpropboundstag = 1;
    12557 conshdlrdata->newsoleventfilterpos = -1;
    12558 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
    12559 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
    12560 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
    12561
    12562 /* include constraint handler */
    12568 conshdlrCopyNonlinear,
    12569 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
    12570 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
    12571 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
    12572 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
    12573 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
    12574 consActiveNonlinear, consDeactiveNonlinear,
    12575 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
    12576 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
    12577 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
    12578 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
    12579
    12580 /* add nonlinear constraint handler parameters */
    12581 /* TODO organize into more subcategories */
    12582 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
    12583 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
    12584 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
    12585
    12586 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
    12587 "whether to check bounds of all auxiliary variable to seed reverse propagation",
    12588 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
    12589
    12590 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
    12591 "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",
    12592 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
    12593
    12594 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
    12595 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
    12596 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
    12597
    12598 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
    12599 "by how much to relax constraint sides during bound tightening",
    12600 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
    12601
    12602 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
    12603 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
    12604 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
    12605
    12606 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
    12607 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
    12608 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    12609
    12610 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
    12611 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
    12612 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
    12613
    12614 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
    12615 "maximal number of auxiliary expressions per bilinear term",
    12616 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
    12617
    12618 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
    12619 "whether to reformulate products of binary variables during presolving",
    12620 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
    12621
    12622 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
    12623 "whether to use the AND constraint handler for reformulating binary products",
    12624 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
    12625
    12626 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
    12627 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
    12628 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
    12629
    12630 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
    12631 "whether to forbid multiaggregation of nonlinear variables",
    12632 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
    12633
    12634 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
    12635 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
    12636 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
    12637
    12638 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
    12639 "whether to (re)run propagation in enforcement",
    12640 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
    12641
    12642 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
    12643 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
    12644 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
    12645
    12646 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
    12647 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
    12648 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
    12649
    12650 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
    12651 "consider efficacy requirement when deciding whether a cut is \"strong\"",
    12652 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
    12653
    12654 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
    12655 "whether to force \"strong\" cuts in enforcement",
    12656 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
    12657
    12658 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
    12659 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
    12660 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
    12661
    12662 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
    12663 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
    12664 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
    12665
    12666 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
    12667 "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",
    12668 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
    12669
    12670 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
    12671 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
    12672 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
    12673
    12674 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
    12675 "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)",
    12676 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
    12677
    12678 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
    12679 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
    12680 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
    12681
    12682 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
    12683 "whether to use external branching candidates and branching rules for branching",
    12684 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
    12685
    12686 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
    12687 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
    12688 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
    12689
    12690 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
    12691 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
    12692 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
    12693
    12694 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
    12695 "weight by how much to consider the violation assigned to a variable for its branching score",
    12696 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12697
    12698 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
    12699 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
    12700 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12701
    12702 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
    12703 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
    12704 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12705
    12706 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
    12707 "weight by how much to consider the pseudo cost of a variable for its branching score",
    12708 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12709
    12710 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
    12711 "weight by how much to consider the domain width in branching score",
    12712 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12713
    12714 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
    12715 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
    12716 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12717
    12718 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
    12719 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
    12720 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
    12721
    12722 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
    12723 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
    12724 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
    12725
    12726 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
    12727 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
    12728 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12729
    12730 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
    12731 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
    12732 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
    12733
    12734 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
    12735 "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)",
    12736 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
    12737
    12738 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
    12739 "whether to assume that any constraint in the presolved problem is convex",
    12740 &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
    12741
    12742 /* include handler for bound change events */
    12743 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
    12744 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
    12745 assert(conshdlrdata->eventhdlr != NULL);
    12746
    12747 /* include tables for statistics */
    12750 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear, tableCollectNonlinear,
    12752
    12755 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr, tableCollectNlhdlr,
    12757
    12758 /* create, include, and release display nlhdlrs dialog */
    12759 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
    12760 {
    12761 SCIP_DIALOG* dialog;
    12762
    12763 assert(parentdialog != NULL);
    12764 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
    12765
    12767 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
    12769 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
    12770 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
    12771 }
    12772
    12773 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
    12774 processNewSolutionEvent, NULL) );
    12775
    12776 return SCIP_OKAY;
    12777}
    12778
    12779/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
    12781 SCIP* scip, /**< SCIP data structure */
    12782 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
    12783 int priority, /**< priority of upgrading method */
    12784 SCIP_Bool active, /**< should the upgrading method by active by default? */
    12785 const char* conshdlrname /**< name of the constraint handler */
    12786 )
    12787{
    12788 SCIP_CONSHDLR* conshdlr;
    12789 SCIP_CONSHDLRDATA* conshdlrdata;
    12790 CONSUPGRADE* consupgrade;
    12792 char paramdesc[SCIP_MAXSTRLEN];
    12793 int i;
    12794
    12795 assert(conshdlrname != NULL );
    12796 assert(nlconsupgd != NULL);
    12797
    12798 /* find the nonlinear constraint handler */
    12799 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12800 if( conshdlr == NULL )
    12801 {
    12802 SCIPerrorMessage("nonlinear constraint handler not found\n");
    12803 return SCIP_PLUGINNOTFOUND;
    12804 }
    12805
    12806 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12807 assert(conshdlrdata != NULL);
    12808
    12809 /* check whether upgrade method exists already */
    12810 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
    12811 {
    12812 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
    12813 {
    12814#ifdef SCIP_DEBUG
    12815 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
    12816#endif
    12817 return SCIP_OKAY;
    12818 }
    12819 }
    12820
    12821 /* create a nonlinear constraint upgrade data object */
    12822 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
    12823 consupgrade->consupgd = nlconsupgd;
    12824 consupgrade->priority = priority;
    12825 consupgrade->active = active;
    12826
    12827 /* insert nonlinear constraint upgrade method into constraint handler data */
    12828 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
    12829 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
    12830
    12831 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
    12832 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
    12833 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
    12834 conshdlrdata->consupgrades[i] = consupgrade;
    12835 conshdlrdata->nconsupgrades++;
    12836
    12837 /* adds parameter to turn on and off the upgrading step */
    12838 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
    12839 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
    12841 paramname, paramdesc,
    12842 &consupgrade->active, FALSE, active, NULL, NULL) );
    12843
    12844 return SCIP_OKAY;
    12845}
    12846
    12847/** creates and captures a nonlinear constraint
    12848 *
    12849 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12850 */
    12852 SCIP* scip, /**< SCIP data structure */
    12853 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12854 const char* name, /**< name of constraint */
    12855 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
    12856 SCIP_Real lhs, /**< left hand side of constraint */
    12857 SCIP_Real rhs, /**< right hand side of constraint */
    12858 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    12859 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    12860 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    12861 * Usually set to TRUE. */
    12862 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    12863 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12864 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    12865 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12866 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    12867 * Usually set to TRUE. */
    12868 SCIP_Bool local, /**< is constraint only valid locally?
    12869 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    12870 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    12871 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    12872 * adds coefficients to this constraint. */
    12873 SCIP_Bool dynamic, /**< is constraint subject to aging?
    12874 * Usually set to FALSE. Set to TRUE for own cuts which
    12875 * are separated as constraints. */
    12876 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
    12877 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    12878 )
    12879{
    12880 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
    12881 SCIP_CONSHDLR* conshdlr;
    12882
    12883 /* find the nonlinear constraint handler */
    12884 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12885 if( conshdlr == NULL )
    12886 {
    12887 SCIPerrorMessage("nonlinear constraint handler not found\n");
    12888 return SCIP_PLUGINNOTFOUND;
    12889 }
    12890
    12891 /* create constraint */
    12892 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
    12893 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12894
    12895 return SCIP_OKAY;
    12896}
    12897
    12898/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
    12899 *
    12900 * All flags can be set via SCIPconsSetFLAGNAME-methods.
    12901 *
    12902 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
    12903 *
    12904 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12905 */
    12907 SCIP* scip, /**< SCIP data structure */
    12908 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12909 const char* name, /**< name of constraint */
    12910 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
    12911 SCIP_Real lhs, /**< left hand side of constraint */
    12912 SCIP_Real rhs /**< right hand side of constraint */
    12913 )
    12914{
    12915 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
    12917
    12918 return SCIP_OKAY;
    12919}
    12920
    12921/** creates and captures a quadratic nonlinear constraint
    12922 *
    12923 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12924 */
    12926 SCIP* scip, /**< SCIP data structure */
    12927 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12928 const char* name, /**< name of constraint */
    12929 int nlinvars, /**< number of linear terms */
    12930 SCIP_VAR** linvars, /**< array with variables in linear part */
    12931 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
    12932 int nquadterms, /**< number of quadratic terms */
    12933 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
    12934 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
    12935 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
    12936 SCIP_Real lhs, /**< left hand side of quadratic equation */
    12937 SCIP_Real rhs, /**< right hand side of quadratic equation */
    12938 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    12939 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    12940 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    12941 * Usually set to TRUE. */
    12942 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    12943 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12944 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    12945 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12946 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    12947 * Usually set to TRUE. */
    12948 SCIP_Bool local, /**< is constraint only valid locally?
    12949 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    12950 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    12951 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    12952 * adds coefficients to this constraint. */
    12953 SCIP_Bool dynamic, /**< is constraint subject to aging?
    12954 * Usually set to FALSE. Set to TRUE for own cuts which
    12955 * are separated as constraints. */
    12956 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
    12957 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    12958 )
    12959{
    12960 SCIP_CONSHDLR* conshdlr;
    12961 SCIP_EXPR* expr;
    12962 int i;
    12963
    12964 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
    12965 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
    12966
    12967 /* check data for infinity or nan values */
    12968 for( i = 0; i < nlinvars; ++i )
    12969 {
    12970 if( !SCIPisFinite(lincoefs[i]) || SCIPisInfinity(scip, lincoefs[i]) )
    12971 {
    12972 SCIPerrorMessage("Infinite or nan coefficient of variable %s in quadratic constraint %s\n", SCIPvarGetName(linvars[i]), name);
    12973 return SCIP_INVALIDDATA;
    12974 }
    12975 }
    12976 for( i = 0; i < nquadterms; ++i )
    12977 {
    12978 if( !SCIPisFinite(quadcoefs[i]) || SCIPisInfinity(scip, quadcoefs[i]) )
    12979 {
    12980 SCIPerrorMessage("Infinite or nan coefficient of term %s*%s in quadratic constraint %s\n", SCIPvarGetName(quadvars1[i]), SCIPvarGetName(quadvars2[i]), name);
    12981 return SCIP_INVALIDDATA;
    12982 }
    12983 }
    12984 /* lhs and rhs will be checked in createCons */
    12985
    12986 /* get nonlinear constraint handler */
    12987 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12988 if( conshdlr == NULL )
    12989 {
    12990 SCIPerrorMessage("nonlinear constraint handler not found\n");
    12991 return SCIP_PLUGINNOTFOUND;
    12992 }
    12993
    12994 /* create quadratic expression */
    12995 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
    12996 assert(expr != NULL);
    12997
    12998 /* create nonlinear constraint */
    12999 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
    13000 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    13001
    13002 /* release quadratic expression (captured by constraint now) */
    13003 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
    13004
    13005 return SCIP_OKAY;
    13006}
    13007
    13008/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
    13009 *
    13010 * All flags can be set via SCIPconsSetFLAGNAME-methods.
    13011 *
    13012 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
    13013 *
    13014 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13015 */
    13017 SCIP* scip, /**< SCIP data structure */
    13018 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13019 const char* name, /**< name of constraint */
    13020 int nlinvars, /**< number of linear terms */
    13021 SCIP_VAR** linvars, /**< array with variables in linear part */
    13022 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
    13023 int nquadterms, /**< number of quadratic terms */
    13024 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
    13025 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
    13026 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
    13027 SCIP_Real lhs, /**< left hand side of quadratic equation */
    13028 SCIP_Real rhs /**< right hand side of quadratic equation */
    13029 )
    13030{
    13031 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
    13033
    13034 return SCIP_OKAY;
    13035}
    13036
    13037/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
    13038 *
    13039 * \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$
    13040 *
    13041 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13042 */
    13044 SCIP* scip, /**< SCIP data structure */
    13045 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13046 const char* name, /**< name of constraint */
    13047 int nvars, /**< number of variables on left hand side of constraint (n) */
    13048 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
    13049 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
    13050 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
    13051 SCIP_Real constant, /**< constant on left hand side (gamma) */
    13052 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
    13053 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
    13054 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
    13055 )
    13056{
    13057 SCIP_EXPR* expr;
    13058 SCIP_EXPR* lhssum;
    13059 SCIP_EXPR* terms[2];
    13060 SCIP_Real termcoefs[2];
    13061 int i;
    13062
    13063 assert(vars != NULL || nvars == 0);
    13064
    13065 /* check values for infinity or nan */
    13066 for( i = 0; i < nvars; ++i )
    13067 {
    13068 if( coefs != NULL && ( !SCIPisFinite(coefs[i]) || SCIPisInfinity(scip, coefs[i]) ) )
    13069 {
    13070 SCIPerrorMessage("Second-order cone term with infinite or nan coefficient of variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
    13071 return SCIP_INVALIDDATA;
    13072 }
    13073 if( offsets != NULL && (!SCIPisFinite(offsets[i]) || SCIPisInfinity(scip, offsets[i])) )
    13074 {
    13075 SCIPerrorMessage("Second-order cone term with infinite or nan offset for variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
    13076 return SCIP_INVALIDDATA;
    13077 }
    13078 }
    13079 if( !SCIPisFinite(constant) || SCIPisInfinity(scip, constant) )
    13080 {
    13081 SCIPerrorMessage("Second-order cone constant with infinite or nan value in nonlinear constraint %s\n", name);
    13082 return SCIP_INVALIDDATA;
    13083 }
    13084 if( !SCIPisFinite(rhscoeff) || SCIPisInfinity(scip, rhscoeff) )
    13085 {
    13086 SCIPerrorMessage("Infinite or nan coefficient of right hand side variable in second-order cone constraint %s\n", name);
    13087 return SCIP_INVALIDDATA;
    13088 }
    13089 if( !SCIPisFinite(rhsoffset) || SCIPisInfinity(scip, rhsoffset) )
    13090 {
    13091 SCIPerrorMessage("Infinite or nan right hand side offset in second-order cone constraint %s\n", name);
    13092 return SCIP_INVALIDDATA;
    13093 }
    13094 /* lhs and rhs will be checked in createCons */
    13095
    13096 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
    13097 for( i = 0; i < nvars; ++i )
    13098 {
    13099 SCIP_EXPR* varexpr;
    13100 SCIP_EXPR* powexpr;
    13101
    13102 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
    13103 if( offsets != NULL && offsets[i] != 0.0 )
    13104 {
    13105 SCIP_EXPR* sum;
    13106 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
    13107 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
    13108 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
    13109 }
    13110 else
    13111 {
    13112 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
    13113 }
    13114
    13115 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
    13116 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
    13117 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
    13118 }
    13119
    13120 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
    13121 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
    13122 termcoefs[0] = 1.0;
    13123
    13124 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
    13125 termcoefs[1] = -rhscoeff;
    13126
    13127 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
    13128
    13129 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
    13130 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
    13131
    13132 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
    13133
    13134 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
    13135
    13136 return SCIP_OKAY;
    13137}
    13138
    13139/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
    13140 *
    13141 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
    13142 *
    13143 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13144 */
    13146 SCIP* scip, /**< SCIP data structure */
    13147 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13148 const char* name, /**< name of constraint */
    13149 SCIP_VAR* x, /**< nonlinear variable x in constraint */
    13150 SCIP_VAR* z, /**< linear variable z in constraint */
    13151 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
    13152 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
    13153 SCIP_Real zcoef, /**< coefficient of z in constraint */
    13154 SCIP_Real lhs, /**< left hand side of constraint */
    13155 SCIP_Real rhs /**< right hand side of constraint */
    13156 )
    13157{
    13158 SCIP_EXPR* xexpr;
    13159 SCIP_EXPR* terms[2];
    13160 SCIP_Real coefs[2];
    13161 SCIP_EXPR* sumexpr;
    13162
    13163 assert(x != NULL);
    13164 assert(z != NULL);
    13165
    13166 if( !SCIPisFinite(exponent) )
    13167 {
    13168 SCIPerrorMessage("exponent in nonlinear signpower constraint <%s> is infinite or nan\n", name);
    13169 return SCIP_INVALIDDATA;
    13170 }
    13171
    13172 if( !SCIPisFinite(xoffset) )
    13173 {
    13174 SCIPerrorMessage("argument offset in nonlinear signpower constraint <%s> is infinite or nan\n", name);
    13175 return SCIP_INVALIDDATA;
    13176 }
    13177
    13178 if( !SCIPisFinite(zcoef) )
    13179 {
    13180 SCIPerrorMessage("coefficient of linear variable in nonlinear signpower constraint <%s> is infinite or nan\n", name);
    13181 return SCIP_INVALIDDATA;
    13182 }
    13183
    13184 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
    13185 if( xoffset != 0.0 )
    13186 {
    13187 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
    13188 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
    13189
    13190 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
    13191 }
    13192 else
    13193 {
    13194 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
    13195 }
    13196 coefs[0] = 1.0;
    13197
    13198 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
    13199 coefs[1] = zcoef;
    13200
    13201 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
    13202
    13203 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
    13204
    13205 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
    13206 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
    13207 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
    13208 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
    13209
    13210 return SCIP_OKAY;
    13211}
    13212
    13213/** gets tag indicating current local variable bounds */
    13215 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13216 )
    13217{
    13218 SCIP_CONSHDLRDATA* conshdlrdata;
    13219
    13220 assert(conshdlr != NULL);
    13221 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13222
    13223 return conshdlrdata->curboundstag;
    13224}
    13225
    13226/** gets the `curboundstag` from the last time where variable bounds were relaxed */
    13228 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13229 )
    13230{
    13231 SCIP_CONSHDLRDATA* conshdlrdata;
    13232
    13233 assert(conshdlr != NULL);
    13234 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13235
    13236 return conshdlrdata->lastboundrelax;
    13237}
    13238
    13239/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
    13240 *
    13241 * @attention This method is not intended for normal use.
    13242 * These tags are maintained by the event handler for variable bound change events.
    13243 * This method is used by some unittests.
    13244 */
    13246 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13247 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
    13248 )
    13249{
    13250 SCIP_CONSHDLRDATA* conshdlrdata;
    13251
    13252 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13253 assert(conshdlrdata != NULL);
    13254
    13255 ++conshdlrdata->curboundstag;
    13256 assert(conshdlrdata->curboundstag > 0);
    13257
    13258 if( boundrelax )
    13259 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
    13260}
    13261
    13262/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
    13264 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13265 )
    13266{
    13267 assert(conshdlr != NULL);
    13268
    13269 return SCIPconshdlrGetData(conshdlr)->var2expr;
    13270}
    13271
    13272/** processes a rowprep for cut addition and maybe report branchscores */
    13274 SCIP* scip, /**< SCIP data structure */
    13275 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
    13276 SCIP_CONS* cons, /**< nonlinear constraint */
    13277 SCIP_EXPR* expr, /**< expression */
    13278 SCIP_ROWPREP* rowprep, /**< cut to be added */
    13279 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
    13280 SCIP_VAR* auxvar, /**< auxiliary variable */
    13281 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
    13282 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
    13283 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
    13284 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
    13285 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
    13286 SCIP_RESULT* result /**< pointer to store the result */
    13287 )
    13288{
    13289 SCIP_Real cutviol;
    13290 SCIP_CONSHDLRDATA* conshdlrdata;
    13291 SCIP_Real auxvarvalue = SCIP_INVALID;
    13292 SCIP_Bool sepasuccess;
    13293 SCIP_Real estimateval = SCIP_INVALID;
    13294 SCIP_Real mincutviolation;
    13295
    13296 assert(nlhdlr != NULL);
    13297 assert(cons != NULL);
    13298 assert(expr != NULL);
    13299 assert(rowprep != NULL);
    13300 assert(auxvar != NULL);
    13301 assert(result != NULL);
    13302
    13303 /* decide on minimal violation of cut */
    13304 if( sol == NULL )
    13305 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
    13306 else
    13307 mincutviolation = SCIPfeastol(scip);
    13308
    13309 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    13310 assert(conshdlrdata != NULL);
    13311
    13312 sepasuccess = TRUE;
    13313
    13314 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
    13315 if( cutviol > 0.0 )
    13316 {
    13317 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
    13318
    13319 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
    13320 if( !allowweakcuts && auxvalue != SCIP_INVALID )
    13321 {
    13322 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
    13323 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
    13324 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
    13325 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
    13326 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
    13327 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
    13328 *
    13329 * if we are overestimating, we have z >= c'x-b >= f(x)
    13330 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
    13331 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
    13332 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
    13333 *
    13334 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
    13335 */
    13336 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
    13337 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
    13338 {
    13339 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
    13340 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
    13341 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
    13342 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
    13343 sepasuccess = FALSE;
    13344 }
    13345 }
    13346
    13347 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
    13348 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
    13349 }
    13350 else
    13351 {
    13352 sepasuccess = FALSE;
    13353 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
    13354 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
    13355 }
    13356
    13357 /* clean up estimator */
    13358 if( sepasuccess )
    13359 {
    13360 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
    13361 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
    13362 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
    13363 SCIPprintRowprep(scip, rowprep, enfologfile); )
    13364
    13365 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
    13366 * instead, may even scale them down, that is, scale so that max coef is close to 1
    13367 */
    13368 if( !allowweakcuts )
    13369 {
    13370 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
    13371
    13372 if( !sepasuccess )
    13373 {
    13374 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
    13375 }
    13376 else
    13377 {
    13378 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
    13379 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
    13380 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
    13381 if( sepasuccess )
    13382 sepasuccess = cutviol > mincutviolation;
    13383 }
    13384
    13385 if( sepasuccess && auxvalue != SCIP_INVALID )
    13386 {
    13387 /* check whether cut is weak now
    13388 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
    13389 * reconstructing estimateval from cutviol (TODO improve or remove?)
    13390 */
    13391 SCIP_Real auxvarcoef = 0.0;
    13392 int i;
    13393
    13394 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
    13395 * it should be...
    13396 */
    13397 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
    13398 {
    13399 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
    13400 {
    13401 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
    13402 break;
    13403 }
    13404 }
    13405
    13406 if( auxvarcoef == 0.0 ||
    13407 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
    13408 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
    13409 {
    13410 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
    13411 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
    13412 sepasuccess = FALSE;
    13413 }
    13414 }
    13415 }
    13416 else
    13417 {
    13418 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
    13419
    13420 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
    13421 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
    13422 */
    13423 if( !branchscoresuccess )
    13425
    13426 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
    13427
    13428 if( !sepasuccess )
    13429 {
    13430 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
    13431 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
    13432 }
    13433
    13434 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
    13435 * changed
    13436 */
    13437 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
    13438 {
    13439 SCIP_Real violscore;
    13440
    13441#ifdef BRSCORE_ABSVIOL
    13442 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
    13443#else
    13444 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
    13445#endif
    13446 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
    13447
    13448 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
    13449 * - were fixed,
    13450 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
    13451 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
    13452 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
    13453 * so I'm disabling the assert for now
    13454 */
    13455 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
    13456 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
    13457 }
    13458 }
    13459 }
    13460
    13461 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
    13462 if( sepasuccess )
    13463 {
    13464 SCIP_ROW* row;
    13465
    13466 if( conshdlrdata->branchdualweight > 0.0 )
    13467 {
    13468 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
    13469 * skip if gap is zero
    13470 */
    13471 if( auxvalue == SCIP_INVALID )
    13472 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
    13473 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
    13474 {
    13475 char gap[40];
    13476 /* coverity[secure_coding] */
    13477 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
    13478 strcat(SCIProwprepGetName(rowprep), gap);
    13479 }
    13480 }
    13481
    13482 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
    13483
    13484 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
    13485 {
    13486 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
    13488 }
    13489 else if( !SCIPisCutApplicable(scip, row) )
    13490 {
    13491 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
    13492 }
    13493 else
    13494 {
    13495 SCIP_Bool infeasible;
    13496
    13497 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
    13498 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
    13499
    13500 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
    13501 * if we haven't found strong cuts before)
    13502 */
    13503 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
    13504
    13505 /* mark row as not removable from LP for current node (this can prevent some cycling) */
    13506 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
    13508
    13509 if( infeasible )
    13510 {
    13511 *result = SCIP_CUTOFF;
    13513 }
    13514 else
    13515 {
    13516 *result = SCIP_SEPARATED;
    13518 }
    13519 }
    13520
    13521 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    13522 }
    13523 else if( branchscoresuccess )
    13524 {
    13525 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
    13526 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
    13527
    13528 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
    13529 * expressions eligible for branching candidate, see enforceConstraints() and branching()
    13530 */
    13531 *result = SCIP_BRANCHED;
    13532 }
    13533 else
    13534 {
    13535 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
    13536 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
    13537 " (!)" : ""); )
    13538 }
    13539
    13540 return SCIP_OKAY;
    13541}
    13542
    13543/** returns whether all nonlinear constraints are assumed to be convex */
    13545 SCIP_CONSHDLR* conshdlr
    13546 )
    13547{
    13548 SCIP_CONSHDLRDATA* conshdlrdata;
    13549
    13550 assert(conshdlr != NULL);
    13551
    13552 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13553 assert(conshdlrdata != NULL);
    13554
    13555 return conshdlrdata->assumeconvex;
    13556}
    13557
    13558/** collects all bilinear terms for a given set of constraints
    13559 *
    13560 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
    13561 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
    13562 */
    13564 SCIP* scip, /**< SCIP data structure */
    13565 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13566 SCIP_CONS** conss, /**< nonlinear constraints */
    13567 int nconss /**< total number of nonlinear constraints */
    13568 )
    13569{
    13570 assert(conshdlr != NULL);
    13571 assert(conss != NULL || nconss == 0);
    13572
    13573 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
    13574
    13575 return SCIP_OKAY;
    13576}
    13577
    13578/** returns the total number of bilinear terms that are contained in all nonlinear constraints
    13579 *
    13580 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13581 */
    13583 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13584 )
    13585{
    13586 SCIP_CONSHDLRDATA* conshdlrdata;
    13587
    13588 assert(conshdlr != NULL);
    13589
    13590 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13591 assert(conshdlrdata != NULL);
    13592
    13593 return conshdlrdata->nbilinterms;
    13594}
    13595
    13596/** returns all bilinear terms that are contained in all nonlinear constraints
    13597 *
    13598 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13599 * @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.
    13600 */
    13602 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13603 )
    13604{
    13605 SCIP_CONSHDLRDATA* conshdlrdata;
    13606
    13607 assert(conshdlr != NULL);
    13608
    13609 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13610 assert(conshdlrdata != NULL);
    13611
    13612 return conshdlrdata->bilinterms;
    13613}
    13614
    13615/** returns the index of the bilinear term representing the product of the two given variables
    13616 *
    13617 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13618 * @return The method returns -1 if the variables do not appear bilinearly.
    13619 */
    13621 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13622 SCIP_VAR* x, /**< first variable */
    13623 SCIP_VAR* y /**< second variable */
    13624 )
    13625{
    13626 SCIP_CONSHDLRDATA* conshdlrdata;
    13628 int idx;
    13629
    13630 assert(conshdlr != NULL);
    13631 assert(x != NULL);
    13632 assert(y != NULL);
    13633
    13634 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13635 assert(conshdlrdata != NULL);
    13636
    13637 if( conshdlrdata->bilinhashtable == NULL )
    13638 {
    13639 return -1;
    13640 }
    13641
    13642 /* ensure that x.index <= y.index */
    13643 if( SCIPvarCompare(x, y) == 1 )
    13644 {
    13645 SCIPswapPointers((void**)&x, (void**)&y);
    13646 }
    13647 assert(SCIPvarCompare(x, y) < 1);
    13648
    13649 /* use a new entry to find the image in the bilinear hash table */
    13650 entry.x = x;
    13651 entry.y = y;
    13652 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
    13653 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
    13654 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
    13655 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
    13656
    13657 return idx;
    13658}
    13659
    13660/** returns the bilinear term that represents the product of two given variables
    13661 *
    13662 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13663 * @return The method returns NULL if the variables do not appear bilinearly.
    13664 */
    13666 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13667 SCIP_VAR* x, /**< first variable */
    13668 SCIP_VAR* y /**< second variable */
    13669 )
    13670{
    13671 SCIP_CONSHDLRDATA* conshdlrdata;
    13672 int idx;
    13673
    13674 assert(conshdlr != NULL);
    13675 assert(x != NULL);
    13676 assert(y != NULL);
    13677
    13678 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13679 assert(conshdlrdata != NULL);
    13680
    13681 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
    13682 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
    13683
    13684 if( idx >= 0 )
    13685 {
    13686 return &conshdlrdata->bilinterms[idx];
    13687 }
    13688
    13689 return NULL;
    13690}
    13691
    13692/** evaluates an auxiliary expression for a bilinear term */
    13694 SCIP* scip, /**< SCIP data structure */
    13695 SCIP_VAR* x, /**< first variable of the bilinear term */
    13696 SCIP_VAR* y, /**< second variable of the bilinear term */
    13697 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
    13698 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
    13699 )
    13700{
    13701 assert(scip != NULL);
    13702 assert(x != NULL);
    13703 assert(y != NULL);
    13704 assert(auxexpr != NULL);
    13705 assert(auxexpr->auxvar != NULL);
    13706
    13707 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
    13708 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
    13709}
    13710
    13711/** stores the variables of a bilinear term in the data of the constraint handler */
    13713 SCIP* scip, /**< SCIP data structure */
    13714 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    13715 SCIP_VAR* x, /**< first variable */
    13716 SCIP_VAR* y, /**< second variable */
    13717 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
    13718 int nlockspos, /**< number of positive expression locks */
    13719 int nlocksneg /**< number of negative expression locks */
    13720 )
    13721{
    13722 SCIP_CONSHDLRDATA* conshdlrdata;
    13724 int idx;
    13725
    13726 assert(conshdlr != NULL);
    13727
    13728 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13729 assert(conshdlrdata != NULL);
    13730
    13731 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
    13732
    13733 term = &conshdlrdata->bilinterms[idx];
    13734 assert(term != NULL);
    13735 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
    13736 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) */
    13737
    13738 /* store and capture auxiliary variable */
    13739 if( auxvar != NULL )
    13740 {
    13741 term->aux.var = auxvar;
    13742 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
    13743 }
    13744
    13745 return SCIP_OKAY;
    13746}
    13747
    13748/** stores the variables of a bilinear term in the data of the constraint handler */
    13750 SCIP* scip, /**< SCIP data structure */
    13751 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    13752 SCIP_VAR* x, /**< first variable */
    13753 SCIP_VAR* y, /**< second variable */
    13754 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
    13755 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
    13756 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
    13757 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
    13758 SCIP_Real cst, /**< constant of the auxiliary expression */
    13759 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
    13760 )
    13761{
    13762 SCIP_CONSHDLRDATA* conshdlrdata;
    13765 int idx;
    13766 int nlockspos;
    13767 int nlocksneg;
    13768 SCIP_Bool added;
    13769
    13770 assert(conshdlr != NULL);
    13771
    13772 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13773 assert(conshdlrdata != NULL);
    13774
    13775 nlockspos = overestimate ? 1 : 0;
    13776 nlocksneg = overestimate ? 0 : 1;
    13777
    13778 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
    13779
    13780 term = &conshdlrdata->bilinterms[idx];
    13781 assert(term != NULL);
    13782 assert(SCIPvarCompare(term->x, term->y) < 1);
    13783
    13784 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
    13785 {
    13786 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
    13787 /* this is the case where we are adding an implicitly defined relation for a product that has already
    13788 * been explicitly defined; convert auxvar into an auxexpr */
    13789
    13790 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
    13791 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
    13792 return SCIP_OKAY;
    13793
    13794 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
    13795 auxvarexpr->cst = 0.0;
    13796 auxvarexpr->coefs[0] = 1.0;
    13797 auxvarexpr->coefs[1] = 0.0;
    13798 auxvarexpr->coefs[2] = 0.0;
    13799 auxvarexpr->auxvar = term->aux.var;
    13800 auxvarexpr->underestimate = term->nlocksneg > 0;
    13801 auxvarexpr->overestimate = term->nlockspos > 0;
    13802
    13803 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
    13804 term->aux.exprs = NULL;
    13805
    13806 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
    13807
    13808 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
    13809 assert(added);
    13810 }
    13811
    13812 /* create and add auxexpr */
    13813 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
    13814 auxexpr->underestimate = !overestimate;
    13815 auxexpr->overestimate = overestimate;
    13816 auxexpr->auxvar = auxvar;
    13817 auxexpr->coefs[0] = coefaux;
    13818 if( term->x == x )
    13819 {
    13820 assert(term->y == y);
    13821 auxexpr->coefs[1] = coefx;
    13822 auxexpr->coefs[2] = coefy;
    13823 }
    13824 else
    13825 {
    13826 assert(term->x == y);
    13827 assert(term->y == x);
    13828 auxexpr->coefs[1] = coefy;
    13829 auxexpr->coefs[2] = coefx;
    13830 }
    13831 auxexpr->cst = cst;
    13832 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
    13833
    13834 if( !added )
    13835 {
    13836 SCIPfreeBlockMemory(scip, &auxexpr);
    13837 }
    13838 else if( auxvar != NULL )
    13839 { /* capture auxiliary variable */
    13840 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
    13841 }
    13842
    13843 return SCIP_OKAY;
    13844}
    13845
    13846/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
    13848 SCIP* scip, /**< SCIP data structure */
    13849 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13850 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
    13851 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
    13852 void* fundata, /**< data for function evaluation (can be NULL) */
    13853 SCIP_Real* xstar, /**< point to be separated */
    13854 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
    13855 int nallvars, /**< half of the length of box */
    13856 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
    13857 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
    13858 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
    13859 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
    13860 )
    13861{
    13862 SCIP_Real* corner;
    13863 SCIP_Real* funvals;
    13864 int* nonfixedpos;
    13865 SCIP_Real maxfaceterror;
    13866 int nvars; /* number of nonfixed variables */
    13867 unsigned int ncorners;
    13868 unsigned int i;
    13869 int j;
    13870
    13871 assert(scip != NULL);
    13872 assert(conshdlr != NULL);
    13873 assert(function != NULL);
    13874 assert(xstar != NULL);
    13875 assert(box != NULL);
    13876 assert(success != NULL);
    13877 assert(facetcoefs != NULL);
    13878 assert(facetconstant != NULL);
    13879
    13880 *success = FALSE;
    13881
    13882 /* identify fixed variables */
    13883 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
    13884 nvars = 0;
    13885 for( j = 0; j < nallvars; ++j )
    13886 {
    13887 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
    13888 continue;
    13889 nonfixedpos[nvars] = j;
    13890 nvars++;
    13891 }
    13892
    13893 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
    13894 * if too many variables are not fixed, then we do nothing currently
    13895 */
    13896 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
    13897 {
    13898 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
    13899 SCIPfreeBufferArray(scip, &nonfixedpos);
    13900 return SCIP_OKAY;
    13901 }
    13902
    13903 /* compute f(v^i) for each corner v^i of [l,u] */
    13904 ncorners = POWEROFTWO(nvars);
    13905 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
    13906 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
    13907 for( j = 0; j < nallvars; ++j )
    13908 {
    13909 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
    13910 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
    13911 }
    13912 for( i = 0; i < ncorners; ++i )
    13913 {
    13914 SCIPdebugMsg(scip, "corner %u: ", i);
    13915 for( j = 0; j < nvars; ++j )
    13916 {
    13917 int varpos = nonfixedpos[j];
    13918 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
    13919 * we check this by shifting i for j positions to the right and checking whether the last bit is set
    13920 */
    13921 if( (i >> j) & 0x1 )
    13922 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
    13923 else
    13924 corner[varpos] = box[2 * varpos ]; /* lb of var */
    13925 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
    13926 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
    13927 }
    13928
    13929 funvals[i] = function(corner, nallvars, fundata);
    13930
    13931 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
    13932
    13933 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
    13934 {
    13935 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
    13936 goto CLEANUP;
    13937 }
    13938 }
    13939
    13940 /* clear coefs array; below we only fill in coefs for nonfixed variables */
    13941 BMSclearMemoryArray(facetcoefs, nallvars);
    13942
    13943 if( nvars == 1 )
    13944 {
    13945 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
    13946
    13947 /* check whether target has been missed */
    13948 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
    13949 {
    13950 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
    13951 *success = FALSE;
    13952 }
    13953 }
    13954 else if( nvars == 2 && SCIPlapackIsAvailable() )
    13955 {
    13956 int idx1 = nonfixedpos[0];
    13957 int idx2 = nonfixedpos[1];
    13958 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
    13959 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
    13960 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
    13961 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
    13962 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
    13963 SCIP_Real coefs[2] = { 0.0, 0.0 };
    13964
    13965 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
    13966
    13967 facetcoefs[idx1] = coefs[0];
    13968 facetcoefs[idx2] = coefs[1];
    13969 }
    13970 else
    13971 {
    13972 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
    13973 }
    13974 if( !*success )
    13975 {
    13976 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
    13977 goto CLEANUP;
    13978 }
    13979
    13980 /*
    13981 * check and adjust facet with the algorithm of Rikun et al.
    13982 */
    13983
    13984 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
    13985
    13986 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
    13987 if( maxfaceterror > 0.0 )
    13988 {
    13989 SCIP_CONSHDLRDATA* conshdlrdata;
    13990 SCIP_Real midval;
    13991 SCIP_Real feastol;
    13992
    13994
    13995 /* evaluate function in middle point to get some idea for a scaling */
    13996 for( j = 0; j < nvars; ++j )
    13997 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
    13998 midval = function(corner, nallvars, fundata);
    13999 if( midval == SCIP_INVALID )
    14000 midval = 1.0;
    14001
    14002 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    14003 assert(conshdlrdata != NULL);
    14004
    14005 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
    14006 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
    14007 {
    14008 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
    14009 *success = FALSE;
    14010 goto CLEANUP;
    14011 }
    14012
    14013 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
    14014
    14015 if( overestimate )
    14016 *facetconstant += maxfaceterror;
    14017 else
    14018 *facetconstant -= maxfaceterror;
    14019 }
    14020
    14021 /* if we made it until here, then we have a nice facet */
    14022 assert(*success);
    14023
    14024CLEANUP:
    14025 /* free allocated memory */
    14026 SCIPfreeBufferArray(scip, &corner);
    14027 SCIPfreeBufferArray(scip, &funvals);
    14028 SCIPfreeBufferArray(scip, &nonfixedpos);
    14029
    14030 return SCIP_OKAY;
    14031}
    14032
    14033/*
    14034 * constraint specific interface methods
    14035 */
    14036
    14037/** returns the expression of the given nonlinear constraint */
    14039 SCIP_CONS* cons /**< constraint data */
    14040 )
    14041{
    14042 SCIP_CONSDATA* consdata;
    14043
    14044 assert(cons != NULL);
    14045 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14046
    14047 consdata = SCIPconsGetData(cons);
    14048 assert(consdata != NULL);
    14049
    14050 return consdata->expr;
    14051}
    14052
    14053/** gets the left hand side of a nonlinear constraint */
    14055 SCIP_CONS* cons /**< constraint data */
    14056 )
    14057{
    14058 SCIP_CONSDATA* consdata;
    14059
    14060 assert(cons != NULL);
    14061 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14062
    14063 consdata = SCIPconsGetData(cons);
    14064 assert(consdata != NULL);
    14065
    14066 return consdata->lhs;
    14067}
    14068
    14069/** gets the right hand side of a nonlinear constraint */
    14071 SCIP_CONS* cons /**< constraint data */
    14072 )
    14073{
    14074 SCIP_CONSDATA* consdata;
    14075
    14076 assert(cons != NULL);
    14077 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14078
    14079 consdata = SCIPconsGetData(cons);
    14080 assert(consdata != NULL);
    14081
    14082 return consdata->rhs;
    14083}
    14084
    14085/** gets the nonlinear constraint as a nonlinear row representation. */
    14087 SCIP* scip, /**< SCIP data structure */
    14088 SCIP_CONS* cons, /**< constraint */
    14089 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
    14090 )
    14091{
    14092 SCIP_CONSDATA* consdata;
    14093
    14094 assert(cons != NULL);
    14095 assert(nlrow != NULL);
    14096 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14097
    14098 consdata = SCIPconsGetData(cons);
    14099 assert(consdata != NULL);
    14100
    14101 if( consdata->nlrow == NULL )
    14102 {
    14103 SCIP_CALL( createNlRow(scip, cons) );
    14104 }
    14105 assert(consdata->nlrow != NULL);
    14106 *nlrow = consdata->nlrow;
    14107
    14108 return SCIP_OKAY;
    14109}
    14110
    14111/** returns the curvature of the expression of a given nonlinear constraint
    14112 *
    14113 * @note The curvature information is computed during CONSINITSOL.
    14114 */
    14116 SCIP_CONS* cons /**< constraint data */
    14117 )
    14118{
    14119 SCIP_CONSDATA* consdata;
    14120
    14121 assert(cons != NULL);
    14122 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14123
    14124 consdata = SCIPconsGetData(cons);
    14125 assert(consdata != NULL);
    14126
    14127 return consdata->curv;
    14128}
    14129
    14130/** checks whether expression of constraint can be represented as quadratic form
    14131 *
    14132 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
    14133 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
    14134 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
    14135 */
    14137 SCIP* scip, /**< SCIP data structure */
    14138 SCIP_CONS* cons, /**< constraint data */
    14139 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
    14140 )
    14141{
    14142 SCIP_CONSDATA* consdata;
    14143
    14144 assert(scip != NULL);
    14145 assert(cons != NULL);
    14146 assert(isquadratic != NULL);
    14147 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14148
    14149 consdata = SCIPconsGetData(cons);
    14150 assert(consdata != NULL);
    14151 assert(consdata->expr != NULL);
    14152
    14153 /* check whether constraint expression is quadratic in extended formulation */
    14154 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
    14155
    14156 /* if not quadratic in non-extended formulation, then do indicate quadratic */
    14157 if( *isquadratic )
    14158 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
    14159
    14160 return SCIP_OKAY;
    14161}
    14162
    14163/** changes left-hand-side of a nonlinear constraint
    14164 *
    14165 * @attention This method can only be called in the problem stage.
    14166 */
    14168 SCIP* scip, /**< SCIP data structure */
    14169 SCIP_CONS* cons, /**< constraint data */
    14170 SCIP_Real lhs /**< new left-hand-side */
    14171 )
    14172{
    14173 SCIP_CONSDATA* consdata;
    14174
    14175 assert(scip != NULL);
    14176 assert(cons != NULL);
    14177 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14178
    14180 {
    14181 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
    14182 return SCIP_INVALIDCALL;
    14183 }
    14184
    14185 /* we should have an original constraint */
    14186 assert(SCIPconsIsOriginal(cons));
    14187
    14188 consdata = SCIPconsGetData(cons);
    14189 assert(consdata != NULL);
    14190
    14191 if( consdata->lhs == lhs )
    14192 return SCIP_OKAY;
    14193
    14194 consdata->lhs = lhs;
    14195
    14196 /* not sure we care about any of these flags for original constraints */
    14197 consdata->ispropagated = FALSE;
    14198
    14199 return SCIP_OKAY;
    14200}
    14201
    14202/** changes right-hand-side of a nonlinear constraint
    14203 *
    14204 * @attention This method can only be called in the problem stage.
    14205 */
    14207 SCIP* scip, /**< SCIP data structure */
    14208 SCIP_CONS* cons, /**< constraint data */
    14209 SCIP_Real rhs /**< new right-hand-side */
    14210 )
    14211{
    14212 SCIP_CONSDATA* consdata;
    14213
    14214 assert(scip != NULL);
    14215 assert(cons != NULL);
    14216 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14217
    14219 {
    14220 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
    14221 return SCIP_INVALIDCALL;
    14222 }
    14223
    14224 /* we should have an original constraint */
    14225 assert(SCIPconsIsOriginal(cons));
    14226
    14227 consdata = SCIPconsGetData(cons);
    14228 assert(consdata != NULL);
    14229
    14230 if( consdata->rhs == rhs )
    14231 return SCIP_OKAY;
    14232
    14233 consdata->rhs = rhs;
    14234
    14235 /* not sure we care about any of these flags for original constraints */
    14236 consdata->ispropagated = FALSE;
    14237
    14238 return SCIP_OKAY;
    14239}
    14240
    14241/** changes expression of a nonlinear constraint
    14242 *
    14243 * @attention This method can only be called in the problem stage.
    14244 */
    14246 SCIP* scip, /**< SCIP data structure */
    14247 SCIP_CONS* cons, /**< constraint data */
    14248 SCIP_EXPR* expr /**< new expression */
    14249 )
    14250{
    14251 SCIP_CONSHDLR* conshdlr;
    14252 SCIP_CONSDATA* consdata;
    14253
    14254 assert(scip != NULL);
    14255 assert(cons != NULL);
    14256 assert(expr != NULL);
    14257
    14259 {
    14260 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
    14261 return SCIP_INVALIDCALL;
    14262 }
    14263
    14264 /* we should have an original constraint */
    14265 assert(SCIPconsIsOriginal(cons));
    14266
    14267 conshdlr = SCIPconsGetHdlr(cons);
    14268 assert(conshdlr != NULL);
    14269 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    14270
    14271 consdata = SCIPconsGetData(cons);
    14272 assert(consdata != NULL);
    14273 assert(consdata->expr != NULL);
    14274
    14275 /* we should not have collected additional data for the expr
    14276 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
    14277 */
    14278 assert(consdata->nvarexprs == 0);
    14279 assert(consdata->varexprs == NULL);
    14280 assert(!consdata->catchedevents);
    14281
    14282 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    14283
    14284 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
    14285 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    14286
    14287 /* not sure we care about any of these flags for original constraints */
    14288 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
    14289 consdata->issimplified = FALSE;
    14290 consdata->ispropagated = FALSE;
    14291
    14292 return SCIP_OKAY;
    14293}
    14294
    14295/** adds coef * var to nonlinear constraint
    14296 *
    14297 * @attention This method can only be called in the problem stage.
    14298 */
    14300 SCIP* scip, /**< SCIP data structure */
    14301 SCIP_CONS* cons, /**< constraint data */
    14302 SCIP_VAR* var, /**< variable */
    14303 SCIP_Real coef /**< coefficient */
    14304 )
    14305{
    14306 SCIP_CONSHDLR* conshdlr;
    14307 SCIP_CONSDATA* consdata;
    14308 SCIP_EXPR* varexpr;
    14309
    14310 assert(scip != NULL);
    14311 assert(cons != NULL);
    14312
    14314 {
    14315 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
    14316 return SCIP_INVALIDCALL;
    14317 }
    14318
    14319 /* we should have an original constraint */
    14320 assert(SCIPconsIsOriginal(cons));
    14321
    14322 if( coef == 0.0 )
    14323 return SCIP_OKAY;
    14324
    14325 conshdlr = SCIPconsGetHdlr(cons);
    14326 assert(conshdlr != NULL);
    14327 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    14328
    14329 consdata = SCIPconsGetData(cons);
    14330 assert(consdata != NULL);
    14331 assert(consdata->expr != NULL);
    14332
    14333 /* we should not have collected additional data for it
    14334 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
    14335 */
    14336 assert(consdata->nvarexprs == 0);
    14337 assert(consdata->varexprs == NULL);
    14338 assert(!consdata->catchedevents);
    14339
    14340 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
    14341
    14342 /* append to sum, if consdata->expr is sum and not used anywhere else */
    14343 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
    14344 {
    14345 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
    14346 }
    14347 else
    14348 {
    14349 /* create new expression = 1 * consdata->expr + coef * var */
    14350 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
    14351 SCIP_Real coefs[2] = { 1.0, coef };
    14352
    14353 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
    14354
    14355 /* release old root expr */
    14356 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
    14357 }
    14358
    14359 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
    14360
    14361 /* not sure we care about any of these flags for original constraints */
    14362 consdata->issimplified = FALSE;
    14363 consdata->ispropagated = FALSE;
    14364
    14365 return SCIP_OKAY;
    14366}
    14367
    14368/** adds coef * expr to nonlinear constraint
    14369 *
    14370 * @attention This method can only be called in the problem stage.
    14371 */
    14373 SCIP* scip, /**< SCIP data structure */
    14374 SCIP_CONS* cons, /**< nonlinear constraint */
    14375 SCIP_EXPR* expr, /**< expression */
    14376 SCIP_Real coef /**< coefficient */
    14377 )
    14378{
    14379 SCIP_CONSHDLR* conshdlr;
    14380 SCIP_CONSDATA* consdata;
    14381 SCIP_EXPR* exprowned;
    14382
    14383 assert(scip != NULL);
    14384 assert(cons != NULL);
    14385
    14387 {
    14388 SCIPerrorMessage("SCIPaddExprNonlinear can only be called in problem stage.\n");
    14389 return SCIP_INVALIDCALL;
    14390 }
    14391
    14392 /* we should have an original constraint */
    14393 assert(SCIPconsIsOriginal(cons));
    14394
    14395 if( coef == 0.0 )
    14396 return SCIP_OKAY;
    14397
    14398 conshdlr = SCIPconsGetHdlr(cons);
    14399 assert(conshdlr != NULL);
    14400 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    14401
    14402 consdata = SCIPconsGetData(cons);
    14403 assert(consdata != NULL);
    14404 assert(consdata->expr != NULL);
    14405
    14406 /* free quadratic representation, if any is stored */
    14407 SCIPfreeExprQuadratic(scip, consdata->expr);
    14408
    14409 /* free varexprs in consdata, in case they have been stored
    14410 * (e.g., by a call to consGet(N)VarsNonlinear)
    14411 */
    14412 SCIP_CALL( freeVarExprs(scip, consdata) );
    14413
    14414 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
    14415 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    14416
    14417 /* append to sum, if consdata->expr is sum and not used anywhere else */
    14418 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
    14419 {
    14420 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
    14421 }
    14422 else
    14423 {
    14424 /* create new expression = 1 * consdata->expr + coef * var */
    14425 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
    14426 SCIP_Real coefs[2] = { 1.0, coef };
    14427
    14428 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
    14429
    14430 /* release old root expr */
    14431 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
    14432 }
    14433
    14434 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
    14435
    14436 /* not sure we care about any of these flags for original constraints */
    14437 consdata->issimplified = FALSE;
    14438 consdata->ispropagated = FALSE;
    14439
    14440 return SCIP_OKAY;
    14441}
    14442
    14443/** computes value of constraint expression in a given solution
    14444 *
    14445 * Stores value of constraint expression in sol in activity.
    14446 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
    14447 */
    14449 SCIP* scip, /**< SCIP data structure */
    14450 SCIP_CONS* cons, /**< constraint */
    14451 SCIP_SOL* sol, /**< solution */
    14452 SCIP_Real* activity /**< buffer to store computed activity */
    14453 )
    14454{
    14455 SCIP_CONSDATA* consdata;
    14456
    14457 assert(cons != NULL);
    14458 assert(activity != NULL);
    14459
    14460 consdata = SCIPconsGetData(cons);
    14461 assert(consdata != NULL);
    14462
    14463 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
    14464 *activity = SCIPexprGetEvalValue(consdata->expr);
    14465
    14466 return SCIP_OKAY;
    14467}
    14468
    14469/** gets absolute violation of nonlinear constraint
    14470 *
    14471 * This function evaluates the constraints in the given solution.
    14472 *
    14473 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
    14474 */
    14476 SCIP* scip, /**< SCIP data structure */
    14477 SCIP_CONS* cons, /**< constraint */
    14478 SCIP_SOL* sol, /**< solution to check */
    14479 SCIP_Real* viol /**< buffer to store computed violation */
    14480 )
    14481{
    14482 assert(cons != NULL);
    14483 assert(viol != NULL);
    14484
    14485 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
    14486 *viol = getConsAbsViolation(cons);
    14487
    14488 return SCIP_OKAY;
    14489}
    14490
    14491/** gets scaled violation of nonlinear constraint
    14492 *
    14493 * This function evaluates the constraints in the given solution.
    14494 *
    14495 * The scaling that is applied to the absolute violation of the constraint
    14496 * depends on the setting of parameter constraints/nonlinear/violscale.
    14497 */
    14499 SCIP* scip, /**< SCIP data structure */
    14500 SCIP_CONS* cons, /**< constraint */
    14501 SCIP_SOL* sol, /**< solution to check */
    14502 SCIP_Real* viol /**< buffer to store computed violation */
    14503 )
    14504{
    14505 assert(cons != NULL);
    14506 assert(viol != NULL);
    14507
    14508 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
    14509 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
    14510
    14511 return SCIP_OKAY;
    14512}
    14513
    14514/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
    14516 SCIP* scip, /**< SCIP data structure */
    14517 SCIP_CONS* cons, /**< nonlinear constraint */
    14518 SCIP_VAR** var, /**< pointer to store the variable */
    14519 SCIP_Real* coef /**< pointer to store the coefficient */
    14520 )
    14521{
    14522 SCIP_CONSDATA* consdata;
    14523
    14524 assert(cons != NULL);
    14525 assert(var != NULL);
    14526 assert(coef != NULL);
    14527
    14528 /* check for a linear variable that can be increased or decreased without harming feasibility */
    14530
    14531 consdata = SCIPconsGetData(cons);
    14532 assert(consdata != NULL);
    14533
    14534 *var = consdata->linvardecr;
    14535 *coef = consdata->linvardecrcoef;
    14536}
    14537
    14538/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
    14540 SCIP* scip, /**< SCIP data structure */
    14541 SCIP_CONS* cons, /**< nonlinear constraint */
    14542 SCIP_VAR** var, /**< pointer to store the variable */
    14543 SCIP_Real* coef /**< pointer to store the coefficient */
    14544 )
    14545{
    14546 SCIP_CONSDATA* consdata;
    14547
    14548 assert(cons != NULL);
    14549 assert(var != NULL);
    14550 assert(coef != NULL);
    14551
    14552 /* check for a linear variable that can be increased or decreased without harming feasibility */
    14554
    14555 consdata = SCIPconsGetData(cons);
    14556 assert(consdata != NULL);
    14557
    14558 *var = consdata->linvarincr;
    14559 *coef = consdata->linvarincrcoef;
    14560}
    14561
    14562
    14563/*
    14564 * Methods for Expressions in Nonlinear Constraints
    14565 */
    14566
    14567/** returns the number of positive rounding locks of an expression */
    14569 SCIP_EXPR* expr /**< expression */
    14570 )
    14571{
    14572 assert(expr != NULL);
    14573 assert(SCIPexprGetOwnerData(expr) != NULL);
    14574
    14575 return SCIPexprGetOwnerData(expr)->nlockspos;
    14576}
    14577
    14578/** returns the number of negative rounding locks of an expression */
    14580 SCIP_EXPR* expr /**< expression */
    14581 )
    14582{
    14583 assert(expr != NULL);
    14584 assert(SCIPexprGetOwnerData(expr) != NULL);
    14585
    14586 return SCIPexprGetOwnerData(expr)->nlocksneg;
    14587}
    14588
    14589/** returns the variable used for linearizing a given expression (return value might be NULL)
    14590 *
    14591 * @note for variable expression it returns the corresponding variable
    14592 */
    14594 SCIP_EXPR* expr /**< expression */
    14595 )
    14596{
    14597 SCIP_EXPR_OWNERDATA* ownerdata;
    14598
    14599 assert(expr != NULL);
    14600
    14601 ownerdata = SCIPexprGetOwnerData(expr);
    14602 assert(ownerdata != NULL);
    14603
    14604 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
    14605}
    14606
    14607/** returns the number of enforcements for an expression */
    14609 SCIP_EXPR* expr /**< expression */
    14610 )
    14611{
    14612 assert(expr != NULL);
    14613 assert(SCIPexprGetOwnerData(expr) != NULL);
    14614
    14615 return SCIPexprGetOwnerData(expr)->nenfos;
    14616}
    14617
    14618/** returns the data for one of the enforcements of an expression */
    14620 SCIP_EXPR* expr, /**< expression */
    14621 int idx, /**< position of enforcement in enfos array */
    14622 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
    14623 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
    14624 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
    14625 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
    14626 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
    14627 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
    14628 )
    14629{
    14630 SCIP_EXPR_OWNERDATA* ownerdata;
    14631
    14632 assert(expr != NULL);
    14633
    14634 ownerdata = SCIPexprGetOwnerData(expr);
    14635 assert(ownerdata != NULL);
    14636 assert(idx >= 0);
    14637 assert(idx < ownerdata->nenfos);
    14638 assert(ownerdata->enfos[idx] != NULL);
    14639 assert(nlhdlr != NULL);
    14640
    14641 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
    14642
    14643 if( nlhdlrexprdata != NULL )
    14644 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
    14645
    14646 if( nlhdlrparticipation != NULL )
    14647 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
    14648
    14649 if( sepabelowusesactivity != NULL )
    14650 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
    14651
    14652 if( sepaaboveusesactivity != NULL )
    14653 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
    14654
    14655 if( auxvalue != NULL )
    14656 *auxvalue = ownerdata->enfos[idx]->auxvalue;
    14657}
    14658
    14659/** sets the auxiliary value of expression for one of the enforcements of an expression */
    14661 SCIP_EXPR* expr, /**< expression */
    14662 int idx, /**< position of enforcement in enfos array */
    14663 SCIP_Real auxvalue /**< the new value of auxval */
    14664 )
    14665{
    14666 SCIP_EXPR_OWNERDATA* ownerdata;
    14667
    14668 assert(expr != NULL);
    14669
    14670 ownerdata = SCIPexprGetOwnerData(expr);
    14671 assert(ownerdata != NULL);
    14672
    14673 assert(idx >= 0);
    14674 assert(idx < ownerdata->nenfos);
    14675 assert(ownerdata->enfos[idx] != NULL);
    14676
    14677 ownerdata->enfos[idx]->auxvalue = auxvalue;
    14678}
    14679
    14680/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
    14681 *
    14682 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
    14683 */
    14685 SCIP_EXPR* expr /**< expression */
    14686 )
    14687{
    14688 assert(expr != NULL);
    14689 assert(SCIPexprGetOwnerData(expr) != NULL);
    14690
    14691 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
    14692}
    14693
    14694/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
    14695 *
    14696 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
    14697 */
    14699 SCIP_EXPR* expr /**< expression */
    14700 )
    14701{
    14702 assert(expr != NULL);
    14703 assert(SCIPexprGetOwnerData(expr) != NULL);
    14704
    14705 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
    14706}
    14707
    14708/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
    14709 *
    14710 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
    14711 */
    14713 SCIP_EXPR* expr /**< expression */
    14714 )
    14715{
    14716 assert(expr != NULL);
    14717 assert(SCIPexprGetOwnerData(expr) != NULL);
    14718
    14719 return SCIPexprGetOwnerData(expr)->nauxvaruses;
    14720}
    14721
    14722/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
    14723 *
    14724 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
    14725 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
    14726 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
    14727 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
    14728 * and also increments this count for all variables in the expression.
    14729 *
    14730 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
    14731 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
    14732 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
    14733 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
    14734 */
    14736 SCIP* scip, /**< SCIP data structure */
    14737 SCIP_EXPR* expr, /**< expression */
    14738 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
    14739 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
    14740 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
    14741 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
    14742 )
    14743{
    14744 SCIP_EXPR_OWNERDATA* ownerdata;
    14745
    14746 assert(expr != NULL);
    14747
    14748 ownerdata = SCIPexprGetOwnerData(expr);
    14749 assert(ownerdata != NULL);
    14750
    14751 /* do not store auxvar request for variable expressions */
    14752 if( useauxvar && SCIPisExprVar(scip, expr) )
    14753 useauxvar = FALSE;
    14754
    14755 if( ownerdata->nenfos >= 0 &&
    14756 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
    14757 (ownerdata->nauxvaruses == 0 && useauxvar)
    14758 ) )
    14759 {
    14760 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
    14761 * we require additional enforcement methods, that is,
    14762 * - activity of expr was not used before but will be used now, or
    14763 * - auxiliary variable of expr was not required before but will be used now
    14764 */
    14765 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
    14766 }
    14767
    14768 if( useauxvar )
    14769 ++ownerdata->nauxvaruses;
    14770
    14771 if( useactivityforprop )
    14772 ++ownerdata->nactivityusesprop;
    14773
    14774 if( useactivityforsepabelow || useactivityforsepaabove )
    14775 ++ownerdata->nactivityusessepa;
    14776
    14777 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
    14778 * information is used in detectNlhdlr()
    14779 */
    14780 if( useactivityforsepabelow )
    14781 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
    14782 if( useactivityforsepaabove )
    14783 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
    14784
    14785 if( useactivityforprop )
    14786 {
    14787 /* if activity will be used for propagation, then make sure there is a valid activity
    14788 * this way, we can do a reversepropcall after detectNlhdlr
    14789 */
    14791 }
    14792
    14793 /* increase the nactivityusedsepa counter for all variables used in the given expression */
    14794 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
    14795 {
    14796 SCIP_EXPRITER* it;
    14797
    14798 /* create and initialize iterator */
    14801
    14802 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    14803 if( SCIPisExprVar(scip, expr) )
    14804 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
    14805
    14806 /* free iterator */
    14807 SCIPfreeExpriter(&it);
    14808 }
    14809
    14810 return SCIP_OKAY;
    14811}
    14812
    14813/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
    14814 *
    14815 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
    14816 * Assume that f(x) is associated with auxiliary variable z.
    14817 *
    14818 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
    14819 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
    14820 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
    14821 *
    14822 * If necessary, f is evaluated in the given solution. If that fails (domain error),
    14823 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
    14824 */
    14826 SCIP* scip, /**< SCIP data structure */
    14827 SCIP_EXPR* expr, /**< expression */
    14828 SCIP_SOL* sol, /**< solution */
    14829 SCIP_Longint soltag, /**< tag of solution */
    14830 SCIP_Real* viol, /**< buffer to store computed violation */
    14831 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
    14832 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
    14833 )
    14834{
    14835 assert(scip != NULL);
    14836 assert(expr != NULL);
    14837 assert(viol != NULL);
    14838
    14839 /* make sure expression has been evaluated */
    14840 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
    14841
    14842 /* get violation from internal method */
    14843 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
    14844
    14845 return SCIP_OKAY;
    14846}
    14847
    14848/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
    14849 *
    14850 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
    14851 * Assume that f(w) is associated with auxiliary variable z.
    14852 *
    14853 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
    14854 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
    14855 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
    14856 *
    14857 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
    14858 * both `violover` and `violunder` are set to TRUE.
    14859 */
    14861 SCIP* scip, /**< SCIP data structure */
    14862 SCIP_EXPR* expr, /**< expression */
    14863 SCIP_Real auxvalue, /**< the value of f(w) */
    14864 SCIP_SOL* sol, /**< solution that has been evaluated */
    14865 SCIP_Real* viol, /**< buffer to store computed violation */
    14866 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
    14867 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
    14868 )
    14869{
    14870 assert(scip != NULL);
    14871 assert(expr != NULL);
    14872 assert(viol != NULL);
    14873
    14874 /* get violation from internal method */
    14875 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
    14876
    14877 return SCIP_OKAY;
    14878}
    14879
    14880
    14881/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
    14882 *
    14883 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
    14884 * Assume that f(w) is associated with auxiliary variable z.
    14885 *
    14886 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
    14887 * the absolute violation divided by max(1,|f(w)|).
    14888 *
    14889 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
    14890 * both `violover` and `violunder` are set to TRUE.
    14891 */
    14893 SCIP* scip, /**< SCIP data structure */
    14894 SCIP_EXPR* expr, /**< expression */
    14895 SCIP_Real auxvalue, /**< the value of f(w) */
    14896 SCIP_SOL* sol, /**< solution that has been evaluated */
    14897 SCIP_Real* viol, /**< buffer to store computed violation */
    14898 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
    14899 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
    14900 )
    14901{
    14902 assert(scip != NULL);
    14903 assert(expr != NULL);
    14904 assert(viol != NULL);
    14905
    14906 /* get violation from internal method */
    14907 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
    14908
    14909 if( !SCIPisInfinity(scip, *viol) )
    14910 {
    14911 assert(auxvalue != SCIP_INVALID);
    14912 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
    14913 *viol /= MAX(1.0, REALABS(auxvalue));
    14914 }
    14915
    14916 return SCIP_OKAY;
    14917}
    14918
    14919/** returns bounds on the expression
    14920 *
    14921 * This gives an intersection of bounds from
    14922 * - activity calculation (SCIPexprGetActivity()), if valid,
    14923 * - auxiliary variable, if present,
    14924 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
    14925 *
    14926 * @note The returned interval can be empty!
    14927 */
    14929 SCIP* scip, /**< SCIP data structure */
    14930 SCIP_EXPR* expr /**< expression */
    14931 )
    14932{
    14933 SCIP_EXPR_OWNERDATA* ownerdata;
    14934 SCIP_CONSHDLRDATA* conshdlrdata;
    14935 SCIP_INTERVAL bounds;
    14936
    14937 assert(scip != NULL);
    14938 assert(expr != NULL);
    14939
    14940 ownerdata = SCIPexprGetOwnerData(expr);
    14941 assert(ownerdata != NULL);
    14942
    14943 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    14944 assert(conshdlrdata != NULL);
    14945
    14946 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
    14947
    14948 /* start with propbounds if they belong to current propagation */
    14949 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
    14950 {
    14951 bounds = ownerdata->propbounds;
    14952 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
    14953 }
    14954 else
    14956
    14957 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
    14958 {
    14959 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
    14960 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
    14962 }
    14963
    14964 if( ownerdata->auxvar != NULL )
    14965 {
    14966 /* apply auxiliary variable bounds to bounds */
    14967 SCIP_INTERVAL auxvarbounds;
    14968
    14969 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
    14970 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
    14971 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
    14972 }
    14973
    14974 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
    14975
    14976 return bounds;
    14977}
    14978
    14979/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
    14980 * corresponding (auxiliary) variable (if any)
    14981 *
    14982 * @attention this function should only be called during domain propagation in cons_nonlinear
    14983 */
    14985 SCIP* scip, /**< SCIP data structure */
    14986 SCIP_EXPR* expr, /**< expression to be tightened */
    14987 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
    14988 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
    14989 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
    14990 )
    14991{
    14992 SCIP_EXPR_OWNERDATA* ownerdata;
    14993 SCIP_CONSHDLRDATA* conshdlrdata;
    14994
    14995 assert(scip != NULL);
    14996 assert(expr != NULL);
    14997 assert(cutoff != NULL);
    14998
    14999 ownerdata = SCIPexprGetOwnerData(expr);
    15000 assert(ownerdata != NULL);
    15001 assert(ownerdata->conshdlr != NULL);
    15002
    15003 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15004 assert(conshdlrdata != NULL);
    15005
    15006 /* the code below assumes that current activity is valid
    15007 * if it turns out that we cannot ensure that, then we should change code
    15008 */
    15009 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
    15011
    15012 *cutoff = FALSE;
    15013
    15014#ifdef DEBUG_PROP
    15015 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
    15016 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    15017 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
    15018#endif
    15019
    15020 if( SCIPexprIsIntegral(expr) )
    15021 {
    15022 /* apply integrality to new bounds
    15023 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
    15024 */
    15025 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
    15026 newbounds.inf = SCIPceil(scip, newbounds.inf);
    15027 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
    15028 newbounds.sup = SCIPfloor(scip, newbounds.sup);
    15029#ifdef DEBUG_PROP
    15030 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
    15031#endif
    15032 }
    15033
    15035 {
    15036 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
    15037
    15038 *cutoff = TRUE;
    15039 return SCIP_OKAY;
    15040 }
    15041
    15042 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
    15043 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
    15044 {
    15045 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
    15046
    15047 *cutoff = TRUE;
    15048 return SCIP_OKAY;
    15049 }
    15050
    15051 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
    15052 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
    15053 {
    15054 /* if already having propbounds in expr, then tighten newbounds by propbounds */
    15055 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
    15056 }
    15057 else
    15058 {
    15059 /* first time we have propbounds for expr in this propagation rounds:
    15060 * intersect with activity (though don't let it become empty if very close intervals)
    15061 */
    15062 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
    15063 }
    15064#ifdef DEBUG_PROP
    15065 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
    15066#endif
    15067
    15068 /* check if the new bounds lead to an empty interval */
    15070 {
    15071 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
    15072
    15073 *cutoff = TRUE;
    15074 return SCIP_OKAY;
    15075 }
    15076
    15077 /* if expr is not constant or variable, then store newbounds in expr->propbounds
    15078 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
    15079 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
    15080 */
    15081 if( SCIPexprGetNChildren(expr) > 0 )
    15082 {
    15083 ownerdata->propbounds = newbounds;
    15084 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
    15085 }
    15086
    15087 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
    15088 * propagation or update of auxvar bounds
    15089 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
    15090 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
    15091 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
    15092 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
    15093 * one or should we not even update propbounds to newbounds if the update is small?
    15094 */
    15095 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
    15096 {
    15097#ifdef DEBUG_PROP
    15098 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);
    15099#endif
    15100 return SCIP_OKAY;
    15101 }
    15102
    15103 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
    15104 {
    15105 /* add expression to propagation queue if not there yet and not var or constant and
    15106 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
    15107 */
    15108#ifdef DEBUG_PROP
    15109 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
    15110#endif
    15111 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
    15112 ownerdata->inpropqueue = TRUE;
    15113 }
    15114
    15115 /* update bounds on variable or auxiliary variable */
    15116 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
    15117
    15118 return SCIP_OKAY;
    15119}
    15120
    15121/** mark constraints that include this expression to be propagated again
    15122 *
    15123 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
    15124 * a change of variable bounds, e.g., because new information on the expression is available
    15125 * that could potentially lead to tighter expression activity values.
    15126 *
    15127 * Note, that this call marks also constraints for propagation which only share some variable
    15128 * with this expression.
    15129 */
    15131 SCIP* scip, /**< SCIP data structure */
    15132 SCIP_EXPR* expr /**< expression to propagate again */
    15133 )
    15134{
    15135 SCIP_EXPRITER* it;
    15136 SCIP_CONSDATA* consdata;
    15137 SCIP_EXPR_OWNERDATA* ownerdata;
    15138 int c;
    15139
    15140 assert(scip != NULL);
    15141 assert(expr != NULL);
    15142
    15143 ownerdata = SCIPexprGetOwnerData(expr);
    15144 assert(ownerdata != NULL);
    15145
    15146 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
    15147
    15150
    15151 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    15152 {
    15153 if( !SCIPisExprVar(scip, expr) )
    15154 continue;
    15155
    15156 ownerdata = SCIPexprGetOwnerData(expr);
    15157 assert(ownerdata != NULL);
    15158
    15159 for( c = 0; c < ownerdata->nconss; ++c )
    15160 {
    15161 consdata = SCIPconsGetData(ownerdata->conss[c]);
    15162 assert(consdata != NULL);
    15163 consdata->ispropagated = FALSE;
    15164 }
    15165 }
    15166
    15167 SCIPfreeExpriter(&it);
    15168
    15169 return SCIP_OKAY;
    15170}
    15171
    15172/** adds violation-branching score to an expression
    15173 *
    15174 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
    15175 * The expression must either be a variable expression or have an aux-variable.
    15176 * In the latter case, branching on auxiliary variables must have been enabled.
    15177 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
    15178 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
    15179 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
    15180 *
    15181 * @see SCIPaddExprsViolScoreNonlinear()
    15182 */
    15184 SCIP* scip, /**< SCIP data structure */
    15185 SCIP_EXPR* expr, /**< expression where to add branching score */
    15186 SCIP_Real violscore /**< violation score to add to expression */
    15187 )
    15188{
    15189 SCIP_EXPR_OWNERDATA* ownerdata;
    15190 SCIP_CONSHDLRDATA* conshdlrdata;
    15191
    15192 assert(scip != NULL);
    15193 assert(expr != NULL);
    15194 assert(violscore >= 0.0);
    15195
    15196 ownerdata = SCIPexprGetOwnerData(expr);
    15197 assert(ownerdata != NULL);
    15198
    15199 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15200 assert(conshdlrdata != NULL);
    15201
    15202 /* if not allowing to branch on auxvars, then expr must be a var-expr */
    15203 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
    15204 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
    15205 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
    15206
    15207 /* reset branching score if we are in a different enfo round */
    15208 if( ownerdata->violscoretag != conshdlrdata->enforound )
    15209 {
    15210 ownerdata->violscoresum = violscore;
    15211 ownerdata->violscoremax = violscore;
    15212 ownerdata->nviolscores = 1;
    15213 ownerdata->violscoretag = conshdlrdata->enforound;
    15214 return;
    15215 }
    15216
    15217 ownerdata->violscoresum += violscore;
    15218 if( violscore > ownerdata->violscoremax )
    15219 ownerdata->violscoremax = violscore;
    15220 ++ownerdata->nviolscores;
    15221}
    15222
    15223/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
    15224 *
    15225 * Each expression must either be a variable expression or have an aux-variable.
    15226 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
    15227 * variables present in `exprs`.
    15228 */
    15230 SCIP* scip, /**< SCIP data structure */
    15231 SCIP_EXPR** exprs, /**< expressions where to add branching score */
    15232 int nexprs, /**< number of expressions */
    15233 SCIP_Real violscore, /**< violation score to add to expression */
    15234 SCIP_SOL* sol, /**< current solution */
    15235 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
    15236 )
    15237{
    15238 SCIP_EXPRITER* it;
    15239 SCIP_EXPR** varexprs;
    15240 SCIP_EXPR* e;
    15241 int nvars;
    15242 int varssize;
    15243 int i;
    15244
    15245 assert(exprs != NULL || nexprs == 0);
    15246 assert(success != NULL);
    15247
    15248 if( nexprs == 0 )
    15249 {
    15250 *success = FALSE;
    15251 return SCIP_OKAY;
    15252 }
    15253
    15254 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
    15255 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
    15256 {
    15257 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
    15258 return SCIP_OKAY;
    15259 }
    15260
    15261 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
    15262 nvars = 0;
    15263 varssize = 5;
    15264 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
    15265
    15268
    15269 for( i = 0; i < nexprs; ++i )
    15270 {
    15271 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
    15272 {
    15273 assert(e != NULL);
    15274
    15275 if( SCIPisExprVar(scip, e) )
    15276 {
    15277 /* add variable expression to vars array */
    15278 if( varssize == nvars )
    15279 {
    15280 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
    15281 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
    15282 }
    15283 assert(varssize > nvars);
    15284
    15285 varexprs[nvars++] = e;
    15286 }
    15287 }
    15288 }
    15289
    15290 SCIPfreeExpriter(&it);
    15291
    15292 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
    15293
    15294 SCIPfreeBufferArray(scip, &varexprs);
    15295
    15296 return SCIP_OKAY;
    15297}
    15298
    15299/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
    15301 SCIP_EXPR* expr /**< expression */
    15302 )
    15303{
    15304 SCIP_EXPR_OWNERDATA* ownerdata;
    15305 SCIP_CONSHDLRDATA* conshdlrdata;
    15306
    15307 assert(expr != NULL);
    15308
    15309 ownerdata = SCIPexprGetOwnerData(expr);
    15310 assert(ownerdata != NULL);
    15311
    15312 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15313 assert(conshdlrdata != NULL);
    15314
    15315 if( conshdlrdata->enforound != ownerdata->violscoretag )
    15316 return 0.0;
    15317
    15318 if( ownerdata->nviolscores == 0 )
    15319 return 0.0;
    15320
    15321 switch( conshdlrdata->branchscoreagg )
    15322 {
    15323 case 'a' :
    15324 /* average */
    15325 return ownerdata->violscoresum / ownerdata->nviolscores;
    15326
    15327 case 'm' :
    15328 /* maximum */
    15329 return ownerdata->violscoremax;
    15330
    15331 case 's' :
    15332 /* sum */
    15333 return ownerdata->violscoresum;
    15334
    15335 default:
    15336 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
    15337 SCIPABORT();
    15338 return SCIP_INVALID;
    15339 }
    15340}
    15341
    15342/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
    15343 *
    15344 * @see SCIPexprGetDerivative()
    15345 */
    15347 SCIP* scip, /**< SCIP data structure */
    15348 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
    15349 SCIP_VAR* var /**< variable (needs to be in the expression) */
    15350 )
    15351{
    15352 SCIP_EXPR_OWNERDATA* ownerdata;
    15353 SCIP_CONSHDLRDATA* conshdlrdata;
    15354 SCIP_EXPR* varexpr;
    15355
    15356 assert(scip != NULL);
    15357 assert(expr != NULL);
    15358 assert(var != NULL);
    15359
    15360 /* return 0.0 for value expression */
    15361 if( SCIPisExprValue(scip, expr) )
    15362 {
    15363 assert(SCIPexprGetDerivative(expr) == 0.0);
    15364 return 0.0;
    15365 }
    15366
    15367 /* check if an error occurred during the last SCIPevalExprGradient() call */
    15368 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
    15369 return SCIP_INVALID;
    15370
    15371 ownerdata = SCIPexprGetOwnerData(expr);
    15372 assert(ownerdata != NULL);
    15373
    15374 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15375 assert(conshdlrdata != NULL);
    15376
    15377 /* use variable to expressions mapping which is stored in the constraint handler data */
    15378 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
    15379
    15380 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
    15381 assert(varexpr != NULL);
    15382 assert(SCIPisExprVar(scip, varexpr));
    15383
    15384 /* use difftag to decide whether the variable belongs to the expression */
    15385 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
    15386}
    15387
    15388/** 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)
    15389 *
    15390 * @see SCIPexprGetBardot()
    15391 */
    15393 SCIP* scip, /**< SCIP data structure */
    15394 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
    15395 SCIP_VAR* var /**< variable (needs to be in the expression) */
    15396 )
    15397{
    15398 SCIP_EXPR_OWNERDATA* ownerdata;
    15399 SCIP_CONSHDLRDATA* conshdlrdata;
    15400 SCIP_EXPR* varexpr;
    15401
    15402 assert(scip != NULL);
    15403 assert(expr != NULL);
    15404 assert(var != NULL);
    15405
    15406 /* return 0.0 for value expression */
    15407 if( SCIPisExprValue(scip, expr) )
    15408 return 0.0;
    15409
    15410 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
    15411 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
    15412 return SCIP_INVALID;
    15413
    15414 ownerdata = SCIPexprGetOwnerData(expr);
    15415 assert(ownerdata != NULL);
    15416
    15417 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15418 assert(conshdlrdata != NULL);
    15419
    15420 /* use variable to expressions mapping which is stored in the constraint handler data;
    15421 * if this fails it means that we are asking for the var's component of H*u for a var
    15422 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
    15423 */
    15424 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
    15425
    15426 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
    15427 assert(varexpr != NULL);
    15428 assert(SCIPisExprVar(scip, varexpr));
    15429
    15430 /* use difftag to decide whether the variable belongs to the expression */
    15431 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
    15432}
    15433
    15434/** evaluates quadratic term in a solution w.r.t. auxiliary variables
    15435 *
    15436 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
    15437 */
    15439 SCIP* scip, /**< SCIP data structure */
    15440 SCIP_EXPR* expr, /**< quadratic expression */
    15441 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
    15442 )
    15443{
    15444 SCIP_Real auxvalue;
    15445 int nlinexprs;
    15446 SCIP_Real* lincoefs;
    15447 SCIP_EXPR** linexprs;
    15448 int nquadexprs;
    15449 int nbilinexprs;
    15450 int i;
    15451
    15452 assert(scip != NULL);
    15453 assert(expr != NULL);
    15454
    15455 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
    15456
    15457 /* linear terms */
    15458 for( i = 0; i < nlinexprs; ++i )
    15459 {
    15460 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
    15461 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
    15462 }
    15463
    15464 /* quadratic terms */
    15465 for( i = 0; i < nquadexprs; ++i )
    15466 {
    15467 SCIP_EXPR* quadexprterm;
    15468 SCIP_Real lincoef;
    15469 SCIP_Real sqrcoef;
    15470 SCIP_Real solval;
    15471
    15472 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
    15473
    15474 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
    15475
    15476 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
    15477 auxvalue += (lincoef + sqrcoef * solval) * solval;
    15478 }
    15479
    15480 /* bilinear terms */
    15481 for( i = 0; i < nbilinexprs; ++i )
    15482 {
    15483 SCIP_EXPR* expr1;
    15484 SCIP_EXPR* expr2;
    15485 SCIP_Real coef;
    15486
    15487 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
    15488
    15489 assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
    15490 assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
    15491 auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
    15492 }
    15493
    15494 return auxvalue;
    15495}
    15496
    15497/**@addtogroup PublicNlhdlrInterfaceMethods
    15498 * @{
    15499 */
    15500
    15501/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
    15503 SCIP* scip, /**< SCIP data structure */
    15504 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
    15505 const char* name, /**< name of nonlinear handler (must not be NULL) */
    15506 const char* desc, /**< description of nonlinear handler (can be NULL) */
    15507 int detectpriority, /**< detection priority of nonlinear handler */
    15508 int enfopriority, /**< enforcement priority of nonlinear handler */
    15509 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
    15510 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
    15511 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
    15512 )
    15513{
    15514 SCIP_CONSHDLR* conshdlr;
    15515 SCIP_CONSHDLRDATA* conshdlrdata;
    15516
    15517 assert(scip != NULL);
    15518 assert(nlhdlr != NULL);
    15519 assert(detect != NULL);
    15520
    15521 /* find myself */
    15522 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    15523 if( conshdlr == NULL )
    15524 {
    15525 SCIPerrorMessage("nonlinear constraint handler not found");
    15526 return SCIP_PLUGINNOTFOUND;
    15527 }
    15528
    15529 /* create nlhdlr */
    15530 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
    15531
    15532 /* include into constraint handler */
    15533 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15534 assert(conshdlrdata != NULL);
    15535
    15536 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
    15537
    15538 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
    15539 ++conshdlrdata->nnlhdlrs;
    15540
    15541 /* sort nonlinear handlers by detection priority, in decreasing order
    15542 * will happen in INIT, so only do when called late
    15543 */
    15544 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
    15545 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
    15546
    15547 return SCIP_OKAY;
    15548}
    15549
    15550/** get number of nonlinear handler */
    15552 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    15553 )
    15554{
    15555 SCIP_CONSHDLRDATA* conshdlrdata;
    15556
    15557 assert(conshdlr != NULL);
    15558
    15559 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15560 assert(conshdlrdata != NULL);
    15561
    15562 return conshdlrdata->nnlhdlrs;
    15563}
    15564
    15565/** get nonlinear handlers */
    15567 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    15568 )
    15569{
    15570 SCIP_CONSHDLRDATA* conshdlrdata;
    15571
    15572 assert(conshdlr != NULL);
    15573
    15574 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15575 assert(conshdlrdata != NULL);
    15576
    15577 return conshdlrdata->nlhdlrs;
    15578}
    15579
    15580/** returns a nonlinear handler of a given name (or NULL if not found) */
    15582 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    15583 const char* name /**< name of nonlinear handler */
    15584 )
    15585{
    15586 SCIP_CONSHDLRDATA* conshdlrdata;
    15587 int h;
    15588
    15589 assert(conshdlr != NULL);
    15590 assert(name != NULL);
    15591
    15592 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15593 assert(conshdlrdata != NULL);
    15594
    15595 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
    15596 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
    15597 return conshdlrdata->nlhdlrs[h];
    15598
    15599 return NULL;
    15600}
    15601
    15602/** gives expression data that a given nonlinear handler stored in an expression
    15603 *
    15604 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
    15605 */
    15607 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
    15608 SCIP_EXPR* expr /**< expression */
    15609 )
    15610{
    15611 SCIP_EXPR_OWNERDATA* ownerdata;
    15612 int e;
    15613
    15614 assert(nlhdlr != NULL);
    15615 assert(expr != NULL);
    15616
    15617 ownerdata = SCIPexprGetOwnerData(expr);
    15618 assert(ownerdata != NULL);
    15619
    15620 for( e = 0; e < ownerdata->nenfos; ++e )
    15621 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
    15622 return ownerdata->enfos[e]->nlhdlrexprdata;
    15623
    15624 return NULL;
    15625}
    15626
    15627/** @} */
    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:312
    #define SCIPdebugAddSolVal(scip, var, val)
    Definition: debug.h:311
    #define NULL
    Definition: def.h:255
    #define SCIP_MAXSTRLEN
    Definition: def.h:276
    #define SCIP_Longint
    Definition: def.h:148
    #define EPSROUND(x, eps)
    Definition: def.h:200
    #define EPSISINT(x, eps)
    Definition: def.h:202
    #define SCIP_REAL_MAX
    Definition: def.h:165
    #define SCIP_INVALID
    Definition: def.h:185
    #define SCIP_INTERVAL_INFINITY
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:98
    #define MIN(x, y)
    Definition: def.h:231
    #define MAX3(x, y, z)
    Definition: def.h:235
    #define SCIP_Real
    Definition: def.h:163
    #define ABS(x)
    Definition: def.h:223
    #define EPSFRAC(x, eps)
    Definition: def.h:201
    #define TRUE
    Definition: def.h:100
    #define FALSE
    Definition: def.h:101
    #define MAX(x, y)
    Definition: def.h:227
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:341
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:155
    #define SCIPABORT()
    Definition: def.h:334
    #define REALABS(x)
    Definition: def.h:189
    #define SCIP_CALL(x)
    Definition: def.h:362
    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:9558
    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:9500
    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:398
    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:3209
    SCIP_Bool SCIPisExprSignpower(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_pow.c:3234
    SCIP_Bool SCIPisExprCos(SCIP *scip, SCIP_EXPR *expr)
    Definition: expr_trig.c:1480
    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:3185
    SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
    Definition: scip_general.c:668
    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:255
    SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
    Definition: heur_subnlp.c:1937
    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:3448
    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:424
    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:884
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1252
    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:608
    SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:1506
    SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
    Definition: scip_sol.c:1719
    void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
    Definition: scip_sol.c:453
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1571
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
    Definition: scip_sol.c:2005
    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:23684
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23479
    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:23387
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4386
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23499
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24269
    SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23507
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23901
    void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
    Definition: var.c:23619
    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:23454
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24143
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23653
    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:23268
    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:23491
    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:24643
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24235
    SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24654
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24121
    SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:11057
    SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR *var)
    Definition: var.c:23464
    int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
    Definition: var.c:17275
    int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4328
    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:753
    SCIP_RETCODE SCIPnlhdlrCollectStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, SCIP_DATATREE *datatree)
    Definition: nlhdlr.c:797
    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:1221
    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