Scippy

    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-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file 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/heur_subnlp.h"
    71#include "scip/heur_trysol.h"
    72#include "scip/lapack_calls.h"
    73#include "scip/debug.h"
    74#include "scip/dialog_default.h"
    75#include "scip/scip_expr.h"
    76#include "scip/symmetry_graph.h"
    77#include "scip/prop_symmetry.h"
    79#include "scip/pub_misc_sort.h"
    80#include "scip/scip_datatree.h"
    81
    82/* fundamental constraint handler properties */
    83#define CONSHDLR_NAME "nonlinear"
    84#define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
    85#define CONSHDLR_ENFOPRIORITY 50 /**< priority of the constraint handler for constraint enforcing */
    86#define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
    87#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
    88 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
    89#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
    90
    91/* optional constraint handler properties */
    92#define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
    93#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
    94#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
    95
    96#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
    97#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
    98#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
    99
    100#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
    101#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
    102
    103/* properties of the nonlinear constraint handler statistics table */
    104#define TABLE_NAME_NONLINEAR "cons_nonlinear"
    105#define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
    106#define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
    107#define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
    108
    109/* properties of the nonlinear handler statistics table */
    110#define TABLE_NAME_NLHDLR "nlhdlr"
    111#define TABLE_DESC_NLHDLR "nonlinear handler statistics"
    112#define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
    113#define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
    114
    115#define DIALOG_NAME "nlhdlrs"
    116#define DIALOG_DESC "display nonlinear handlers"
    117#define DIALOG_ISSUBMENU FALSE
    118
    119#define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
    120#define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
    121#define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
    122#define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
    123
    124#define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
    125
    126#define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
    127
    128/** translate from one value of infinity to another
    129 *
    130 * if val is &ge; infty1, then give infty2, else give val
    131 */
    132#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
    133
    134/** translates x to 2^x for non-negative integer x */
    135#define POWEROFTWO(x) (0x1u << (x))
    136
    137#ifdef ENFO_LOGGING
    138#define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
    139FILE* enfologfile = NULL;
    140#else
    141#define ENFOLOG(x)
    142#endif
    143
    144/*
    145 * Data structures
    146 */
    147
    148/** enforcement data of an expression */
    149typedef struct
    150{
    151 SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
    152 SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
    153 SCIP_NLHDLR_METHOD nlhdlrparticipation;/**< methods where nonlinear handler participates */
    154 SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
    155 SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
    156 SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
    157 SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
    158} EXPRENFO;
    159
    160/** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
    161struct SCIP_Expr_OwnerData
    162{
    163 SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
    164
    165 /* locks and monotonicity */
    166 int nlockspos; /**< positive locks counter */
    167 int nlocksneg; /**< negative locks counter */
    168 SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
    169 int monotonicitysize; /**< length of monotonicity array */
    170
    171 /* propagation (in addition to activity that is stored in expr) */
    172 SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
    173 unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
    174 SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
    175
    176 /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
    177 EXPRENFO** enfos; /**< enforcements */
    178 int nenfos; /**< number of enforcements, or -1 if not initialized */
    179 unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
    180 unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
    181 unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
    182 unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
    183 SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
    184
    185 /* branching */
    186 SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
    187 SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
    188 int nviolscores; /**< number of violation scores stored for this expression */
    189 unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
    190
    191 /* additional data for variable expressions (TODO move into sub-struct?) */
    192 SCIP_CONS** conss; /**< constraints in which this variable appears */
    193 int nconss; /**< current number of constraints in conss */
    194 int consssize; /**< length of conss array */
    195 SCIP_Bool consssorted; /**< is the array of constraints sorted */
    196
    197 int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
    198};
    199
    200/** constraint data for nonlinear constraints */
    201struct SCIP_ConsData
    202{
    203 /* data that defines the constraint: expression and sides */
    204 SCIP_EXPR* expr; /**< expression that represents this constraint */
    205 SCIP_Real lhs; /**< left-hand side */
    206 SCIP_Real rhs; /**< right-hand side */
    207
    208 /* variables */
    209 SCIP_EXPR** varexprs; /**< array containing all variable expressions */
    210 int nvarexprs; /**< total number of variable expressions */
    211 SCIP_Bool catchedevents; /**< do we catch events on variables? */
    212
    213 /* constraint violation */
    214 SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
    215 SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
    216 SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
    217 SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
    218
    219 /* status flags */
    220 unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
    221 unsigned int issimplified:1; /**< did we simplify the expression tree already? */
    222
    223 /* locks */
    224 int nlockspos; /**< number of positive locks */
    225 int nlocksneg; /**< number of negative locks */
    226
    227 /* repair infeasible solutions */
    228 SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
    229 SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
    230 SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
    231 SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
    232
    233 /* miscellaneous */
    234 SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
    235 SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
    236 int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
    237};
    238
    239/** constraint upgrade method */
    240typedef struct
    241{
    242 SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
    243 int priority; /**< priority of upgrading method */
    244 SCIP_Bool active; /**< is upgrading enabled */
    246
    247/** constraint handler data */
    248struct SCIP_ConshdlrData
    249{
    250 /* nonlinear handler */
    251 SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
    252 int nnlhdlrs; /**< number of nonlinear handlers */
    253 int nlhdlrssize; /**< size of nlhdlrs array */
    254 SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
    255 SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
    256 SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
    257
    258 /* constraint upgrades */
    259 CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
    260 int consupgradessize; /**< size of consupgrades array */
    261 int nconsupgrades; /**< number of constraint upgrade methods */
    262
    263 /* other plugins */
    264 SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
    265 SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
    266 SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
    267
    268 /* tags and counters */
    269 int auxvarid; /**< unique id for the next auxiliary variable */
    270 SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
    271 SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
    272 SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
    273 unsigned int enforound; /**< total number of enforcement calls, including current one */
    274 int lastconsindex; /**< last used consindex, plus one */
    275
    276 /* activity intervals and domain propagation */
    277 SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
    278 SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
    279 SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
    280 SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
    281 unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
    282
    283 /* parameters */
    284 int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
    285 SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
    286 char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
    287 SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
    288 SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
    289 SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
    290 SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
    291 SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
    292 SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
    293 SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
    294 int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
    295 SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
    296 SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
    297 SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
    298 SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
    299 SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
    300 SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
    301 SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
    302 SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
    303 SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
    304 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 */
    305 char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
    306 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) */
    307 int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
    308 SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
    309 SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
    310 SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
    311 SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
    312 SCIP_Real branchfracweight; /**< weight by how much to consider fractionality of integer variables in branching score for spatial branching */
    313 SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
    314 SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
    315 SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
    316 SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
    317 char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
    318 char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
    319 SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
    320 SCIP_Real branchmixfractional; /**< minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables */
    321 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) */
    322 SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
    323
    324 /* statistics */
    325 SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
    326 SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
    327 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 */
    328 SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
    329 SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
    330 SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
    331 SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
    332 SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
    333
    334 /* facets of envelops of vertex-polyhedral functions */
    335 SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
    336 SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
    337
    338 /* hashing of bilinear terms */
    339 SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
    340 SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
    341 int nbilinterms; /**< total number of bilinear terms */
    342 int bilintermssize; /**< size of bilinterms array */
    343 int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
    344
    345 /* branching */
    346 SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
    347 char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
    348
    349 /* misc */
    350 SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
    351 SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
    352 int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
    353};
    354
    355/** branching candidate with various scores */
    356typedef struct
    357{
    358 SCIP_EXPR* expr; /**< expression that holds branching candidate, NULL if candidate is due to fractionality of integer variable */
    359 SCIP_VAR* var; /**< variable that is branching candidate */
    360 SCIP_Real auxviol; /**< aux-violation score of candidate */
    361 SCIP_Real domain; /**< domain score of candidate */
    362 SCIP_Real dual; /**< dual score of candidate */
    363 SCIP_Real pscost; /**< pseudo-cost score of candidate */
    364 SCIP_Real vartype; /**< variable type score of candidate */
    365 SCIP_Real fractionality; /**< fractionality score of candidate */
    366 SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
    367} BRANCHCAND;
    368
    369/*
    370 * Local methods
    371 */
    372
    373/* forward declaration */
    374static
    376 SCIP* scip, /**< SCIP data structure */
    377 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    378 SCIP_EXPR* rootexpr, /**< expression */
    379 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
    380 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
    381 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
    382 );
    383
    384/** frees auxiliary variables of expression, if any */
    385static
    387 SCIP* scip, /**< SCIP data structure */
    388 SCIP_EXPR* expr /**< expression which auxvar to free, if any */
    389 )
    390{
    391 SCIP_EXPR_OWNERDATA* mydata;
    392
    393 assert(scip != NULL);
    394 assert(expr != NULL);
    395
    396 mydata = SCIPexprGetOwnerData(expr);
    397 assert(mydata != NULL);
    398
    399 if( mydata->auxvar == NULL )
    400 return SCIP_OKAY;
    401
    402 SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
    403
    404 /* remove variable locks
    405 * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
    406 */
    407 SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
    408
    409 /* release auxiliary variable */
    410 SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
    411 assert(mydata->auxvar == NULL);
    412
    413 return SCIP_OKAY;
    414}
    415
    416/** frees data used for enforcement of expression, that is, nonlinear handlers
    417 *
    418 * can also clear indicators whether expr needs enforcement methods, that is,
    419 * free an associated auxiliary variable and reset the nactivityuses counts
    420 */
    421static
    423 SCIP* scip, /**< SCIP data structure */
    424 SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
    425 SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
    426 )
    427{
    428 SCIP_EXPR_OWNERDATA* mydata;
    429 int e;
    430
    431 mydata = SCIPexprGetOwnerData(expr);
    432 assert(mydata != NULL);
    433
    434 if( freeauxvar )
    435 {
    436 /* free auxiliary variable */
    437 SCIP_CALL( freeAuxVar(scip, expr) );
    438 assert(mydata->auxvar == NULL);
    439
    440 /* reset count on activity and auxvar usage */
    441 mydata->nactivityusesprop = 0;
    442 mydata->nactivityusessepa = 0;
    443 mydata->nauxvaruses = 0;
    444 }
    445
    446 /* free data stored by nonlinear handlers */
    447 for( e = 0; e < mydata->nenfos; ++e )
    448 {
    449 SCIP_NLHDLR* nlhdlr;
    450
    451 assert(mydata->enfos[e] != NULL);
    452
    453 nlhdlr = mydata->enfos[e]->nlhdlr;
    454 assert(nlhdlr != NULL);
    455
    456 if( mydata->enfos[e]->issepainit )
    457 {
    458 /* call the separation deinitialization callback of the nonlinear handler */
    459 SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
    460 mydata->enfos[e]->issepainit = FALSE;
    461 }
    462
    463 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
    464 if( mydata->enfos[e]->nlhdlrexprdata != NULL )
    465 {
    466 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
    467 assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
    468 }
    469
    470 /* free enfo data */
    471 SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
    472 }
    473
    474 /* free array with enfo data */
    475 SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
    476
    477 /* we need to look at this expression in detect again */
    478 mydata->nenfos = -1;
    479
    480 return SCIP_OKAY;
    481}
    482
    483/** callback that frees data that this conshdlr stored in an expression */
    484static
    486{
    487 assert(scip != NULL);
    488 assert(expr != NULL);
    489 assert(ownerdata != NULL);
    490 assert(*ownerdata != NULL);
    491
    492 /* expression should not be locked anymore */
    493 assert((*ownerdata)->nlockspos == 0);
    494 assert((*ownerdata)->nlocksneg == 0);
    495
    496 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
    497
    498 /* expression should not be enforced anymore */
    499 assert((*ownerdata)->nenfos <= 0);
    500 assert((*ownerdata)->auxvar == NULL);
    501
    502 if( SCIPisExprVar(scip, expr) )
    503 {
    504 SCIP_CONSHDLRDATA* conshdlrdata;
    505 SCIP_VAR* var;
    506
    507 /* there should be no constraints left that still use this variable */
    508 assert((*ownerdata)->nconss == 0);
    509 /* thus, there should also be no variable event catched (via this exprhdlr) */
    510 assert((*ownerdata)->filterpos == -1);
    511
    512 SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
    513
    514 /* update var2expr hashmap in conshdlrdata */
    515 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
    516 assert(conshdlrdata != NULL);
    517
    518 var = SCIPgetVarExprVar(expr);
    519 assert(var != NULL);
    520
    521 /* remove var -> expr map from hashmap if present
    522 * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
    523 * if variable-expression stored for var is different, then also do nothing)
    524 */
    525 if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
    526 {
    527 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
    528 }
    529 }
    530
    531 SCIPfreeBlockMemory(scip, ownerdata);
    532
    533 return SCIP_OKAY;
    534}
    535
    536static
    538{ /*lint --e{715}*/
    539 assert(ownerdata != NULL);
    540
    541 /* print nl handlers associated to expr */
    542 if( ownerdata->nenfos > 0 )
    543 {
    544 int i;
    545 SCIPinfoMessage(scip, file, " {");
    546
    547 for( i = 0; i < ownerdata->nenfos; ++i )
    548 {
    549 SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
    550 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
    551 SCIPinfoMessage(scip, file, "a");
    552 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
    553 SCIPinfoMessage(scip, file, "u");
    554 if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
    555 SCIPinfoMessage(scip, file, "o");
    556 if( i < ownerdata->nenfos-1 )
    557 SCIPinfoMessage(scip, file, ", ");
    558 }
    559
    560 SCIPinfoMessage(scip, file, "}");
    561 }
    562
    563 /* print aux var associated to expr */
    564 if( ownerdata->auxvar != NULL )
    565 {
    566 SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
    567 }
    568 SCIPinfoMessage(scip, file, "\n");
    569
    570 return SCIP_OKAY;
    571}
    572
    573/** possibly reevaluates and then returns the activity of the expression
    574 *
    575 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
    576 */
    577static
    579{
    580 SCIP_CONSHDLRDATA* conshdlrdata;
    581
    582 assert(scip != NULL);
    583 assert(expr != NULL);
    584 assert(ownerdata != NULL);
    585
    586 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    587 assert(conshdlrdata != NULL);
    588
    589 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
    590 {
    591 /* update activity of expression */
    592 SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
    593
    594 assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
    595 }
    596
    597 return SCIP_OKAY;
    598}
    599
    600/** callback that creates data that this conshdlr wants to store in an expression */
    601static
    603{
    604 assert(scip != NULL);
    605 assert(expr != NULL);
    606 assert(ownerdata != NULL);
    607
    609 (*ownerdata)->nenfos = -1;
    610 (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
    611
    612 if( SCIPisExprVar(scip, expr) )
    613 {
    614 SCIP_CONSHDLRDATA* conshdlrdata;
    615 SCIP_VAR* var;
    616
    617 (*ownerdata)->filterpos = -1;
    618
    619 /* add to var2expr hashmap if not having expr for var yet */
    620
    621 conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
    622 assert(conshdlrdata != NULL);
    623
    624 var = SCIPgetVarExprVar(expr);
    625
    626 if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
    627 {
    628 /* store the variable expression in the hashmap */
    629 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
    630 }
    631 else
    632 {
    633 /* if expr was just created, then it shouldn't already be stored as image of var */
    634 assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
    635 }
    636 }
    637 else
    638 {
    639 /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
    640 (*ownerdata)->filterpos = -2;
    641 }
    642
    643 *ownerfree = exprownerFree;
    644 *ownerprint = exprownerPrint;
    645 *ownerevalactivity = exprownerEvalactivity;
    646
    647 return SCIP_OKAY;
    648}
    649
    650/** creates a variable expression or retrieves from hashmap in conshdlr data */
    651static
    653 SCIP* scip, /**< SCIP data structure */
    654 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    655 SCIP_EXPR** expr, /**< pointer where to store expression */
    656 SCIP_VAR* var /**< variable to be stored */
    657 )
    658{
    659 assert(conshdlr != NULL);
    660 assert(expr != NULL);
    661 assert(var != NULL);
    662
    663 /* get variable expression representing the given variable if there is one already */
    664 *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
    665
    666 if( *expr == NULL )
    667 {
    668 /* create a new variable expression; this also captures the expression */
    669 SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
    670 assert(*expr != NULL);
    671 /* exprownerCreate should have added var->expr to var2expr */
    672 assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
    673 }
    674 else
    675 {
    676 /* only capture already existing expr to get a consistent uses-count */
    677 SCIPcaptureExpr(*expr);
    678 }
    679
    680 return SCIP_OKAY;
    681}
    682
    683/* map var exprs to var-expr from var2expr hashmap */
    684static
    686{ /*lint --e{715}*/
    687 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
    688
    689 assert(sourcescip != NULL);
    690 assert(targetscip != NULL);
    691 assert(sourceexpr != NULL);
    692 assert(targetexpr != NULL);
    693 assert(*targetexpr == NULL);
    694 assert(mapexprdata != NULL);
    695
    696 /* do not provide map if not variable */
    697 if( !SCIPisExprVar(sourcescip, sourceexpr) )
    698 return SCIP_OKAY;
    699
    700 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
    701
    702 return SCIP_OKAY;
    703}
    704
    705/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
    706static
    708{ /*lint --e{715}*/
    709 SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
    710 SCIP_VAR* var;
    711
    712 assert(sourcescip != NULL);
    713 assert(targetscip != NULL);
    714 assert(sourceexpr != NULL);
    715 assert(targetexpr != NULL);
    716 assert(*targetexpr == NULL);
    717 assert(mapexprdata != NULL);
    718
    719 /* do not provide map if not variable */
    720 if( !SCIPisExprVar(sourcescip, sourceexpr) )
    721 return SCIP_OKAY;
    722
    723 var = SCIPgetVarExprVar(sourceexpr);
    724 assert(var != NULL);
    725
    726 /* transform variable */
    727 SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
    728 assert(var != NULL);
    729
    730 SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
    731
    732 return SCIP_OKAY;
    733}
    734
    735/** stores all variable expressions into a given constraint */
    736static
    738 SCIP* scip, /**< SCIP data structure */
    739 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    740 SCIP_CONSDATA* consdata /**< constraint data */
    741 )
    742{
    743 SCIP_CONSHDLRDATA* conshdlrdata;
    744 int varexprssize;
    745 int i;
    746
    747 assert(consdata != NULL);
    748
    749 /* skip if we have stored the variable expressions already */
    750 if( consdata->varexprs != NULL )
    751 return SCIP_OKAY;
    752
    753 assert(consdata->varexprs == NULL);
    754 assert(consdata->nvarexprs == 0);
    755
    756 /* get an upper bound on number of variable expressions */
    757 if( consdata->issimplified )
    758 {
    759 /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
    760 * so we cannot have more variable expression than the number of active variables
    761 */
    762 varexprssize = SCIPgetNVars(scip);
    763 }
    764 else
    765 {
    766 SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
    767 }
    768
    769 /* create array to store all variable expressions */
    770 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
    771
    772 SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
    773 assert(varexprssize >= consdata->nvarexprs);
    774
    775 /* shrink array if there are less variables in the expression than in the problem */
    776 if( varexprssize > consdata->nvarexprs )
    777 {
    778 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
    779 }
    780
    781 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    782 assert(conshdlrdata != NULL);
    783 assert(conshdlrdata->var2expr != NULL);
    784
    785 /* ensure that for every variable an entry exists in the var2expr hashmap
    786 * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
    787 */
    788 for( i = 0; i < consdata->nvarexprs; ++i )
    789 {
    790 if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
    791 {
    792 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
    793 }
    794 }
    795
    796 return SCIP_OKAY;
    797}
    798
    799/** frees all variable expression stored in storeVarExprs() */
    800static
    802 SCIP* scip, /**< SCIP data structure */
    803 SCIP_CONSDATA* consdata /**< constraint data */
    804 )
    805{
    806 int i;
    807
    808 assert(consdata != NULL);
    809
    810 /* skip if we have stored the variable expressions already */
    811 if( consdata->varexprs == NULL )
    812 return SCIP_OKAY;
    813
    814 assert(consdata->varexprs != NULL);
    815 assert(consdata->nvarexprs >= 0);
    816 assert(!consdata->catchedevents);
    817
    818 /* release variable expressions */
    819 for( i = 0; i < consdata->nvarexprs; ++i )
    820 {
    821 assert(consdata->varexprs[i] != NULL);
    822 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
    823 assert(consdata->varexprs[i] == NULL);
    824 }
    825
    826 /* free variable expressions */
    827 SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
    828 consdata->varexprs = NULL;
    829 consdata->nvarexprs = 0;
    830
    831 return SCIP_OKAY;
    832}
    833
    834/** interval evaluation of variables as used in bound tightening
    835 *
    836 * Returns slightly relaxed local variable bounds of a variable as interval.
    837 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
    838 */
    839static
    840SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
    841{
    842 SCIP_INTERVAL interval;
    843 SCIP_CONSHDLRDATA* conshdlrdata;
    844 SCIP_Real lb;
    845 SCIP_Real ub;
    846
    847 assert(scip != NULL);
    848 assert(var != NULL);
    849
    850 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
    851 assert(conshdlrdata != NULL);
    852
    853 if( conshdlrdata->globalbounds )
    854 {
    855 lb = SCIPvarGetLbGlobal(var);
    856 ub = SCIPvarGetUbGlobal(var);
    857 }
    858 else
    859 {
    860 lb = SCIPvarGetLbLocal(var);
    861 ub = SCIPvarGetUbLocal(var);
    862 }
    863 assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
    864
    865 /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
    866 if( SCIPvarIsImpliedIntegral(var) )
    867 {
    868 lb = EPSROUND(lb, 0.0); /*lint !e835*/
    869 ub = EPSROUND(ub, 0.0); /*lint !e835*/
    870 }
    871
    872 /* integer variables should always have integral bounds in SCIP */
    873 assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
    874 assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
    875
    876 switch( conshdlrdata->varboundrelax )
    877 {
    878 case 'n' : /* no relaxation */
    879 break;
    880
    881 case 'a' : /* relax by absolute value */
    882 {
    883 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
    884 if( SCIPvarIsIntegral(var) )
    885 break;
    886
    887 if( !SCIPisInfinity(scip, -lb) )
    888 {
    889 /* reduce lb by epsilon, or to the next integer value, which ever is larger */
    890 SCIP_Real bnd = floor(lb);
    891 lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
    892 }
    893
    894 if( !SCIPisInfinity(scip, ub) )
    895 {
    896 /* increase ub by epsilon, or to the next integer value, which ever is smaller */
    897 SCIP_Real bnd = ceil(ub);
    898 ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
    899 }
    900
    901 break;
    902 }
    903
    904 case 'b' : /* relax always by absolute value */
    905 {
    906 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
    907 if( SCIPvarIsIntegral(var) )
    908 break;
    909
    910 if( !SCIPisInfinity(scip, -lb) )
    911 lb -= conshdlrdata->varboundrelaxamount;
    912
    913 if( !SCIPisInfinity(scip, ub) )
    914 ub += conshdlrdata->varboundrelaxamount;
    915
    916 break;
    917 }
    918
    919 case 'r' : /* relax by relative value */
    920 {
    921 /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
    922 if( SCIPvarIsIntegral(var) )
    923 break;
    924
    925 /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
    926 * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
    927 * further, do not relax beyond next integer value
    928 */
    929 if( !SCIPisInfinity(scip, -lb) )
    930 {
    931 SCIP_Real bnd = floor(lb);
    932 lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
    933 }
    934
    935 if( !SCIPisInfinity(scip, ub) )
    936 {
    937 SCIP_Real bnd = ceil(ub);
    938 ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
    939 }
    940
    941 break;
    942 }
    943
    944 default :
    945 {
    946 SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
    947 SCIPABORT();
    948 break;
    949 }
    950 }
    951
    952 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
    955 assert(lb <= ub);
    956
    957 SCIPintervalSetBounds(&interval, lb, ub);
    958
    959 return interval;
    960}
    961
    962/** compares two nonlinear constraints by its index
    963 *
    964 * Usable as compare operator in array sort functions.
    965 */
    966static
    967SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
    968{
    969 SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
    970 SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
    971
    972 assert(consdata1 != NULL);
    973 assert(consdata2 != NULL);
    974
    975 return consdata1->consindex - consdata2->consindex;
    976}
    977
    978/** processes variable fixing or bound change event */
    979static
    980SCIP_DECL_EVENTEXEC(processVarEvent)
    981{ /*lint --e{715}*/
    982 SCIP_EVENTTYPE eventtype;
    983 SCIP_EXPR* expr;
    984 SCIP_EXPR_OWNERDATA* ownerdata;
    985 SCIP_Bool boundtightened = FALSE;
    986
    987 eventtype = SCIPeventGetType(event);
    989
    990 assert(eventdata != NULL);
    991 expr = (SCIP_EXPR*) eventdata;
    992 assert(SCIPisExprVar(scip, expr));
    993
    994 SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
    998
    999 ownerdata = SCIPexprGetOwnerData(expr);
    1000 assert(ownerdata != NULL);
    1001 /* we only catch varevents for variables in constraints, so there should be constraints */
    1002 assert(ownerdata->nconss > 0);
    1003 assert(ownerdata->conss != NULL);
    1004
    1005 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
    1006 boundtightened = TRUE;
    1007
    1008 /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
    1009 * however, if the boundchange is smaller than epsilon, such an event will be omitted
    1010 * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
    1011 * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
    1012 * as a boundtightening (and usually it is, I would think)
    1013 */
    1014 if( eventtype & SCIP_EVENTTYPE_VARFIXED )
    1015 boundtightened = TRUE;
    1016
    1017 /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
    1018 * because we will round the bounds and no longer consider relaxing them
    1019 * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
    1020 * (mainly to avoid a failing assert, see github issue #70)
    1021 * 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
    1022 */
    1024 && ( !EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) /*lint !e835*/
    1025 || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0) ) ) /*lint !e835*/
    1026 boundtightened = TRUE;
    1027
    1028 /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
    1029 * - propagation can only find something new if a bound was tightened
    1030 * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
    1031 * and we look at global changes (that is, we are not looking at boundchanges in probing)
    1032 */
    1033 if( boundtightened )
    1034 {
    1035 SCIP_CONSDATA* consdata;
    1036 int c;
    1037
    1038 for( c = 0; c < ownerdata->nconss; ++c )
    1039 {
    1040 assert(ownerdata->conss[c] != NULL);
    1041 consdata = SCIPconsGetData(ownerdata->conss[c]);
    1042
    1043 /* if bound tightening, then mark constraints to be propagated again
    1044 * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
    1045 * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
    1046 * the locks don't help since they are not available separately for each constraint
    1047 */
    1048 consdata->ispropagated = FALSE;
    1049 SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
    1050
    1051 /* if still in presolve (but not probing), then mark constraints to be unsimplified */
    1053 {
    1054 consdata->issimplified = FALSE;
    1055 SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
    1056 }
    1057 }
    1058 }
    1059
    1060 /* update curboundstag, lastboundrelax, and expr activity */
    1061 if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
    1062 {
    1063 SCIP_CONSHDLRDATA* conshdlrdata;
    1064 SCIP_INTERVAL activity;
    1065
    1066 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    1067 assert(conshdlrdata != NULL);
    1068
    1069 /* increase tag on bounds */
    1070 ++conshdlrdata->curboundstag;
    1071 assert(conshdlrdata->curboundstag > 0);
    1072
    1073 /* remember also if we relaxed bounds now */
    1074 if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
    1075 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
    1076
    1077 /* update the activity of the var-expr here immediately
    1078 * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
    1079 */
    1080 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
    1081 /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
    1082#ifdef DEBUG_PROP
    1083 SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
    1084#endif
    1085 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
    1086 }
    1087
    1088 return SCIP_OKAY;
    1089}
    1090
    1091/** registers event handler to catch variable events on variable
    1092 *
    1093 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
    1094 * When an event occurs, all stored constraints are notified.
    1095 */
    1096static
    1098 SCIP* scip, /**< SCIP data structure */
    1099 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1100 SCIP_EXPR* expr, /**< variable expression */
    1101 SCIP_CONS* cons /**< nonlinear constraint */
    1102 )
    1103{
    1104 SCIP_EXPR_OWNERDATA* ownerdata;
    1105
    1106 assert(eventhdlr != NULL);
    1107 assert(expr != NULL);
    1108 assert(SCIPisExprVar(scip, expr));
    1109 assert(cons != NULL);
    1110
    1111 ownerdata = SCIPexprGetOwnerData(expr);
    1112 assert(ownerdata != NULL);
    1113
    1114#ifndef NDEBUG
    1115 /* assert that constraint does not double-catch variable */
    1116 {
    1117 int i;
    1118 for( i = 0; i < ownerdata->nconss; ++i )
    1119 assert(ownerdata->conss[i] != cons);
    1120 }
    1121#endif
    1122
    1123 /* append cons to ownerdata->conss */
    1124 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
    1125 ownerdata->conss[ownerdata->nconss++] = cons;
    1126 /* we're not capturing the constraint here to avoid circular references */
    1127
    1128 /* updated sorted flag */
    1129 if( ownerdata->nconss <= 1 )
    1130 ownerdata->consssorted = TRUE;
    1131 else if( ownerdata->consssorted )
    1132 ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) < 0;
    1133
    1134 /* catch variable events, if not done so yet (first constraint) */
    1135 if( ownerdata->filterpos < 0 )
    1136 {
    1137 SCIP_EVENTTYPE eventtype;
    1138
    1139 assert(ownerdata->nconss == 1);
    1140
    1142
    1143 SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
    1144 assert(ownerdata->filterpos >= 0);
    1145 }
    1146
    1147 return SCIP_OKAY;
    1148}
    1149
    1150/** catch variable events */
    1151static
    1153 SCIP* scip, /**< SCIP data structure */
    1154 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1155 SCIP_CONS* cons /**< constraint for which to catch bound change events */
    1156 )
    1157{
    1158 SCIP_CONSHDLRDATA* conshdlrdata;
    1159 SCIP_CONSDATA* consdata;
    1160 SCIP_EXPR* expr;
    1161 int i;
    1162
    1163 assert(eventhdlr != NULL);
    1164 assert(cons != NULL);
    1165
    1166 consdata = SCIPconsGetData(cons);
    1167 assert(consdata != NULL);
    1168 assert(consdata->varexprs != NULL);
    1169 assert(consdata->nvarexprs >= 0);
    1170
    1171 /* check if we have catched variable events already */
    1172 if( consdata->catchedevents )
    1173 return SCIP_OKAY;
    1174
    1175 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    1176 assert(conshdlrdata != NULL);
    1177#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
    1178 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
    1179#endif
    1180
    1181 SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
    1182
    1183 for( i = 0; i < consdata->nvarexprs; ++i )
    1184 {
    1185 expr = consdata->varexprs[i];
    1186
    1187 assert(expr != NULL);
    1188 assert(SCIPisExprVar(scip, expr));
    1189
    1190 SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
    1191
    1192 /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
    1193 * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
    1194 */
    1195 if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
    1196 {
    1197 SCIP_INTERVAL activity;
    1198 SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
    1199 /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
    1200 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
    1201#ifdef DEBUG_PROP
    1202 SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
    1203#endif
    1204 }
    1205 }
    1206
    1207 consdata->catchedevents = TRUE;
    1208
    1209 return SCIP_OKAY;
    1210}
    1211
    1212/** unregisters event handler to catch variable events on variable
    1213 *
    1214 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
    1215 * If this was the last constraint, then the event handler is unregistered for this variable.
    1216 */
    1217static
    1219 SCIP* scip, /**< SCIP data structure */
    1220 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1221 SCIP_EXPR* expr, /**< variable expression */
    1222 SCIP_CONS* cons /**< expr constraint */
    1223 )
    1224{
    1225 SCIP_EXPR_OWNERDATA* ownerdata;
    1226 int pos;
    1227
    1228 assert(eventhdlr != NULL);
    1229 assert(expr != NULL);
    1230 assert(SCIPisExprVar(scip, expr));
    1231 assert(cons != NULL);
    1232
    1233 ownerdata = SCIPexprGetOwnerData(expr);
    1234 assert(ownerdata != NULL);
    1235 assert(ownerdata->nconss > 0);
    1236
    1237 if( ownerdata->conss[ownerdata->nconss-1] == cons )
    1238 {
    1239 pos = ownerdata->nconss-1;
    1240 }
    1241 else
    1242 {
    1243 if( !ownerdata->consssorted )
    1244 {
    1245 SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
    1246 ownerdata->consssorted = TRUE;
    1247 }
    1248
    1249 if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
    1250 {
    1251 SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
    1252 return SCIP_ERROR;
    1253 }
    1254 assert(pos >= 0 && pos < ownerdata->nconss);
    1255 }
    1256 assert(ownerdata->conss[pos] == cons);
    1257
    1258 /* move last constraint into position of removed constraint */
    1259 if( pos < ownerdata->nconss-1 )
    1260 {
    1261 ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
    1262 ownerdata->consssorted = FALSE;
    1263 }
    1264 --ownerdata->nconss;
    1265
    1266 /* drop variable events if that was the last constraint */
    1267 if( ownerdata->nconss == 0 )
    1268 {
    1269 SCIP_EVENTTYPE eventtype;
    1270
    1271 assert(ownerdata->filterpos >= 0);
    1272
    1274
    1275 SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
    1276 ownerdata->filterpos = -1;
    1277 }
    1278
    1279 return SCIP_OKAY;
    1280}
    1281
    1282/** drop variable events */
    1283static
    1285 SCIP* scip, /**< SCIP data structure */
    1286 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
    1287 SCIP_CONS* cons /**< constraint for which to drop bound change events */
    1288 )
    1289{
    1290 SCIP_CONSDATA* consdata;
    1291 int i;
    1292
    1293 assert(eventhdlr != NULL);
    1294 assert(cons != NULL);
    1295
    1296 consdata = SCIPconsGetData(cons);
    1297 assert(consdata != NULL);
    1298
    1299 /* check if we have catched variable events already */
    1300 if( !consdata->catchedevents )
    1301 return SCIP_OKAY;
    1302
    1303 assert(consdata->varexprs != NULL);
    1304 assert(consdata->nvarexprs >= 0);
    1305
    1306 SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
    1307
    1308 for( i = consdata->nvarexprs - 1; i >= 0; --i )
    1309 {
    1310 assert(consdata->varexprs[i] != NULL);
    1311
    1312 SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
    1313 }
    1314
    1315 consdata->catchedevents = FALSE;
    1316
    1317 return SCIP_OKAY;
    1318}
    1319
    1320/** creates and captures a nonlinear constraint
    1321 *
    1322 * @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
    1323 */
    1324static
    1326 SCIP* scip, /**< SCIP data structure */
    1327 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    1328 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    1329 const char* name, /**< name of constraint */
    1330 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
    1331 SCIP_Real lhs, /**< left hand side of constraint */
    1332 SCIP_Real rhs, /**< right hand side of constraint */
    1333 SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
    1334 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    1335 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    1336 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    1337 * Usually set to TRUE. */
    1338 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    1339 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    1340 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    1341 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    1342 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    1343 * Usually set to TRUE. */
    1344 SCIP_Bool local, /**< is constraint only valid locally?
    1345 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    1346 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    1347 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    1348 * adds coefficients to this constraint. */
    1349 SCIP_Bool dynamic, /**< is constraint subject to aging?
    1350 * Usually set to FALSE. Set to TRUE for own cuts which
    1351 * are separated as constraints. */
    1352 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
    1353 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    1354 )
    1355{
    1356 SCIP_CONSHDLRDATA* conshdlrdata;
    1357 SCIP_CONSDATA* consdata;
    1358
    1359 assert(conshdlr != NULL);
    1360 assert(expr != NULL);
    1361
    1362 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1363 assert(conshdlrdata != NULL);
    1364
    1365 if( local && SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
    1366 {
    1367 SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
    1368 return SCIP_INVALIDCALL;
    1369 }
    1370
    1371 /* TODO we should allow for non-initial nonlinear constraints */
    1372 if( !initial )
    1373 {
    1374 SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
    1375 return SCIP_INVALIDCALL;
    1376 }
    1377
    1378 if( isnan(lhs) || isnan(rhs) )
    1379 {
    1380 SCIPerrorMessage("%s hand side of nonlinear constraint <%s> is nan\n",
    1381 isnan(lhs) ? "left" : "right", name);
    1382 return SCIP_INVALIDDATA;
    1383 }
    1384
    1385 /* create constraint data */
    1387
    1388 if( copyexpr )
    1389 {
    1390 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
    1391 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    1392 }
    1393 else
    1394 {
    1395 consdata->expr = expr;
    1396 SCIPcaptureExpr(consdata->expr);
    1397 }
    1398 consdata->lhs = lhs;
    1399 consdata->rhs = rhs;
    1400 consdata->consindex = conshdlrdata->lastconsindex++;
    1401 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
    1402
    1403 /* create constraint */
    1404 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    1405 local, modifiable, dynamic, removable, FALSE) );
    1406
    1407 return SCIP_OKAY;
    1408}
    1409
    1410/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
    1411 *
    1412 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
    1413 * Assume that f(x) is associated with auxiliary variable z.
    1414 *
    1415 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
    1416 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
    1417 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
    1418 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
    1419 *
    1420 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
    1421 */
    1422static
    1424 SCIP* scip, /**< SCIP data structure */
    1425 SCIP_EXPR* expr, /**< expression */
    1426 SCIP_SOL* sol, /**< solution that has been evaluated */
    1427 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
    1428 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
    1429 )
    1430{
    1431 SCIP_EXPR_OWNERDATA* ownerdata;
    1432 SCIP_Real auxvarvalue;
    1433
    1434 assert(expr != NULL);
    1435
    1436 ownerdata = SCIPexprGetOwnerData(expr);
    1437 assert(ownerdata != NULL);
    1438 assert(ownerdata->auxvar != NULL);
    1439
    1440 if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
    1441 {
    1442 if( violunder != NULL )
    1443 *violunder = TRUE;
    1444 if( violover != NULL )
    1445 *violover = TRUE;
    1446 return SCIPinfinity(scip);
    1447 }
    1448
    1449 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
    1450
    1451 if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
    1452 {
    1453 if( violunder != NULL )
    1454 *violunder = FALSE;
    1455 if( violover != NULL )
    1456 *violover = TRUE;
    1457 return auxvarvalue - SCIPexprGetEvalValue(expr);
    1458 }
    1459
    1460 if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
    1461 {
    1462 if( violunder != NULL )
    1463 *violunder = TRUE;
    1464 if( violover != NULL )
    1465 *violover = FALSE;
    1466 return SCIPexprGetEvalValue(expr) - auxvarvalue;
    1467 }
    1468
    1469 if( violunder != NULL )
    1470 *violunder = FALSE;
    1471 if( violover != NULL )
    1472 *violover = FALSE;
    1473 return 0.0;
    1474}
    1475
    1476/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
    1477 *
    1478 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
    1479 * Assume that f(w) is associated with auxiliary variable z.
    1480 *
    1481 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
    1482 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
    1483 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
    1484 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
    1485 *
    1486 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
    1487 */
    1488static
    1490 SCIP* scip, /**< SCIP data structure */
    1491 SCIP_EXPR* expr, /**< expression */
    1492 SCIP_Real auxvalue, /**< value of f(w) */
    1493 SCIP_SOL* sol, /**< solution that has been evaluated */
    1494 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
    1495 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
    1496 )
    1497{
    1498 SCIP_EXPR_OWNERDATA* ownerdata;
    1499 SCIP_Real auxvarvalue;
    1500
    1501 assert(expr != NULL);
    1502
    1503 ownerdata = SCIPexprGetOwnerData(expr);
    1504 assert(ownerdata != NULL);
    1505 assert(ownerdata->auxvar != NULL);
    1506
    1507 if( auxvalue == SCIP_INVALID )
    1508 {
    1509 if( violunder != NULL )
    1510 *violunder = TRUE;
    1511 if( violover != NULL )
    1512 *violover = TRUE;
    1513 return SCIPinfinity(scip);
    1514 }
    1515
    1516 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
    1517
    1518 if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
    1519 {
    1520 if( violunder != NULL )
    1521 *violunder = FALSE;
    1522 if( violover != NULL )
    1523 *violover = TRUE;
    1524 return auxvarvalue - auxvalue;
    1525 }
    1526
    1527 if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
    1528 {
    1529 if( violunder != NULL )
    1530 *violunder = TRUE;
    1531 if( violover != NULL )
    1532 *violover = FALSE;
    1533 return auxvalue - auxvarvalue;
    1534 }
    1535
    1536 if( violunder != NULL )
    1537 *violunder = FALSE;
    1538 if( violover != NULL )
    1539 *violover = FALSE;
    1540
    1541 return 0.0;
    1542}
    1543
    1544/** computes violation of a constraint */
    1545static
    1547 SCIP* scip, /**< SCIP data structure */
    1548 SCIP_CONS* cons, /**< constraint */
    1549 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
    1550 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
    1551 )
    1552{
    1553 SCIP_CONSDATA* consdata;
    1554 SCIP_Real activity;
    1555
    1556 assert(scip != NULL);
    1557 assert(cons != NULL);
    1558
    1559 consdata = SCIPconsGetData(cons);
    1560 assert(consdata != NULL);
    1561
    1562 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
    1563 activity = SCIPexprGetEvalValue(consdata->expr);
    1564
    1565 /* consider constraint as violated if it is undefined in the current point */
    1566 if( activity == SCIP_INVALID )
    1567 {
    1568 consdata->lhsviol = SCIPinfinity(scip);
    1569 consdata->rhsviol = SCIPinfinity(scip);
    1570 return SCIP_OKAY;
    1571 }
    1572
    1573 /* compute violations */
    1574 consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
    1575 consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
    1576
    1577 return SCIP_OKAY;
    1578}
    1579
    1580/** returns absolute violation of a constraint
    1581 *
    1582 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
    1583 */
    1584static
    1586 SCIP_CONS* cons /**< constraint */
    1587 )
    1588{
    1589 SCIP_CONSDATA* consdata;
    1590
    1591 assert(cons != NULL);
    1592
    1593 consdata = SCIPconsGetData(cons);
    1594 assert(consdata != NULL);
    1595
    1596 return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
    1597}
    1598
    1599/** computes relative violation of a constraint
    1600 *
    1601 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
    1602 */
    1603static
    1605 SCIP* scip, /**< SCIP data structure */
    1606 SCIP_CONS* cons, /**< constraint */
    1607 SCIP_Real* viol, /**< buffer to store violation */
    1608 SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
    1609 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
    1610 )
    1611{
    1612 SCIP_CONSHDLR* conshdlr;
    1613 SCIP_CONSHDLRDATA* conshdlrdata;
    1614 SCIP_CONSDATA* consdata;
    1615 SCIP_Real scale;
    1616
    1617 assert(cons != NULL);
    1618 assert(viol != NULL);
    1619
    1620 conshdlr = SCIPconsGetHdlr(cons);
    1621 assert(conshdlr != NULL);
    1622
    1623 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1624 assert(conshdlrdata != NULL);
    1625
    1626 *viol = getConsAbsViolation(cons);
    1627
    1628 if( conshdlrdata->violscale == 'n' )
    1629 return SCIP_OKAY;
    1630
    1631 if( SCIPisInfinity(scip, *viol) )
    1632 return SCIP_OKAY;
    1633
    1634 consdata = SCIPconsGetData(cons);
    1635 assert(consdata != NULL);
    1636
    1637 if( conshdlrdata->violscale == 'a' )
    1638 {
    1639 scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
    1640
    1641 /* consider value of side that is violated for scaling, too */
    1642 if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
    1643 {
    1644 assert(!SCIPisInfinity(scip, -consdata->lhs));
    1645 scale = REALABS(consdata->lhs);
    1646 }
    1647 else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
    1648 {
    1649 assert(!SCIPisInfinity(scip, consdata->rhs));
    1650 scale = REALABS(consdata->rhs);
    1651 }
    1652
    1653 *viol /= scale;
    1654 return SCIP_OKAY;
    1655 }
    1656
    1657 /* if not 'n' or 'a', then it has to be 'g' at the moment */
    1658 assert(conshdlrdata->violscale == 'g');
    1659 if( soltag == 0L || consdata->gradnormsoltag != soltag )
    1660 {
    1661 /* we need the varexprs to conveniently access the gradient */
    1662 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    1663
    1664 /* update cached value of norm of gradient */
    1665 consdata->gradnorm = 0.0;
    1666
    1667 /* compute gradient */
    1668 SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
    1669
    1670 /* gradient evaluation error -> no scaling */
    1671 if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
    1672 {
    1673 int i;
    1674 for( i = 0; i < consdata->nvarexprs; ++i )
    1675 {
    1676 SCIP_Real deriv;
    1677
    1678 assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
    1679 deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
    1680 if( deriv == SCIP_INVALID )
    1681 {
    1682 /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
    1683 consdata->gradnorm = 0.0;
    1684 break;
    1685 }
    1686
    1687 consdata->gradnorm += deriv*deriv;
    1688 }
    1689 }
    1690 consdata->gradnorm = sqrt(consdata->gradnorm);
    1691 consdata->gradnormsoltag = soltag;
    1692 }
    1693
    1694 *viol /= MAX(1.0, consdata->gradnorm);
    1695
    1696 return SCIP_OKAY;
    1697}
    1698
    1699/** returns whether constraint is currently violated
    1700 *
    1701 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
    1702 */
    1703static
    1705 SCIP* scip, /**< SCIP data structure */
    1706 SCIP_CONS* cons /**< constraint */
    1707 )
    1708{
    1709 return getConsAbsViolation(cons) > SCIPfeastol(scip);
    1710}
    1711
    1712/** checks for a linear variable that can be increased or decreased without harming feasibility */
    1713static
    1715 SCIP* scip, /**< SCIP data structure */
    1716 SCIP_CONS* cons /**< constraint */
    1717 )
    1718{
    1719 SCIP_CONSDATA* consdata;
    1720 int poslock;
    1721 int neglock;
    1722 int i;
    1723
    1724 assert(cons != NULL);
    1725
    1726 consdata = SCIPconsGetData(cons);
    1727 assert(consdata != NULL);
    1728
    1729 consdata->linvarincr = NULL;
    1730 consdata->linvardecr = NULL;
    1731 consdata->linvarincrcoef = 0.0;
    1732 consdata->linvardecrcoef = 0.0;
    1733
    1734 /* root expression is not a sum -> no unlocked linear variable available */
    1735 if( !SCIPisExprSum(scip, consdata->expr) )
    1736 return;
    1737
    1738 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
    1739 {
    1740 SCIP_EXPR* child;
    1741
    1742 child = SCIPexprGetChildren(consdata->expr)[i];
    1743 assert(child != NULL);
    1744
    1745 /* check whether the child is a variable expression */
    1746 if( SCIPisExprVar(scip, child) )
    1747 {
    1748 SCIP_VAR* var = SCIPgetVarExprVar(child);
    1749 SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
    1750
    1751 if( coef > 0.0 )
    1752 {
    1753 poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
    1754 neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
    1755 }
    1756 else
    1757 {
    1758 poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
    1759 neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
    1760 }
    1762
    1763 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
    1764 {
    1765 /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
    1766 * if we have already one candidate, then take the one where the loss in the objective function is less
    1767 */
    1768 if( (consdata->linvardecr == NULL) ||
    1769 (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
    1770 {
    1771 consdata->linvardecr = var;
    1772 consdata->linvardecrcoef = coef;
    1773 }
    1774 }
    1775
    1776 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
    1777 {
    1778 /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
    1779 * if we have already one candidate, then take the one where the loss in the objective function is less
    1780 */
    1781 if( (consdata->linvarincr == NULL) ||
    1782 (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
    1783 {
    1784 consdata->linvarincr = var;
    1785 consdata->linvarincrcoef = coef;
    1786 }
    1787 }
    1788 }
    1789 }
    1790
    1791 assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
    1792 assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
    1793
    1794 if( consdata->linvarincr != NULL )
    1795 {
    1796 SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
    1797 }
    1798 if( consdata->linvardecr != NULL )
    1799 {
    1800 SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
    1801 }
    1802}
    1803
    1804/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
    1805 * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
    1806 *
    1807 * The method assumes that this is always possible and that not all constraints are feasible already.
    1808 */
    1809static
    1811 SCIP* scip, /**< SCIP data structure */
    1812 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    1813 SCIP_CONS** conss, /**< constraints to process */
    1814 int nconss, /**< number of constraints */
    1815 SCIP_SOL* sol, /**< solution to process */
    1816 SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
    1817 )
    1818{
    1819 SCIP_CONSHDLRDATA* conshdlrdata;
    1820 SCIP_SOL* newsol;
    1821 int c;
    1822
    1823 assert(scip != NULL);
    1824 assert(conshdlr != NULL);
    1825 assert(conss != NULL || nconss == 0);
    1826 assert(success != NULL);
    1827
    1828 *success = FALSE;
    1829
    1830 /* don't propose new solutions if not in presolve or solving */
    1832 return SCIP_OKAY;
    1833
    1834 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    1835 assert(conshdlrdata != NULL);
    1836
    1837 if( sol != NULL )
    1838 {
    1839 SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
    1840 }
    1841 else
    1842 {
    1843 SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
    1844 }
    1845 SCIP_CALL( SCIPunlinkSol(scip, newsol) );
    1846 SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
    1847 sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
    1848
    1849 for( c = 0; c < nconss; ++c )
    1850 {
    1851 SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
    1852 SCIP_Real viol = 0.0;
    1853 SCIP_Real delta;
    1854 SCIP_Real gap;
    1855
    1856 assert(consdata != NULL);
    1857
    1858 /* get absolute violation and sign */
    1859 if( consdata->lhsviol > SCIPfeastol(scip) )
    1860 viol = consdata->lhsviol; /* lhs - activity */
    1861 else if( consdata->rhsviol > SCIPfeastol(scip) )
    1862 viol = -consdata->rhsviol; /* rhs - activity */
    1863 else
    1864 continue; /* constraint is satisfied */
    1865
    1866 if( consdata->linvarincr != NULL &&
    1867 ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
    1868 {
    1869 SCIP_VAR* var = consdata->linvarincr;
    1870
    1871 /* compute how much we would like to increase var */
    1872 delta = viol / consdata->linvarincrcoef;
    1873 assert(delta > 0.0);
    1874
    1875 /* if var has an upper bound, may need to reduce delta */
    1877 {
    1878 gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
    1879 delta = MIN(MAX(0.0, gap), delta);
    1880 }
    1881 if( SCIPisPositive(scip, delta) )
    1882 {
    1883 /* if variable is integral, round delta up so that it will still have an integer value */
    1884 if( SCIPvarIsIntegral(var) )
    1885 delta = SCIPceil(scip, delta);
    1886
    1887 SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
    1888 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
    1889 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
    1890
    1891 /* adjust constraint violation, if satisfied go on to next constraint */
    1892 viol -= consdata->linvarincrcoef * delta;
    1893 if( SCIPisZero(scip, viol) )
    1894 continue;
    1895 }
    1896 }
    1897
    1898 assert(viol != 0.0);
    1899 if( consdata->linvardecr != NULL &&
    1900 ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
    1901 {
    1902 SCIP_VAR* var = consdata->linvardecr;
    1903
    1904 /* compute how much we would like to decrease var */
    1905 delta = viol / consdata->linvardecrcoef;
    1906 assert(delta < 0.0);
    1907
    1908 /* if var has a lower bound, may need to reduce delta */
    1910 {
    1911 gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
    1912 delta = MAX(MIN(0.0, gap), delta);
    1913 }
    1914 if( SCIPisNegative(scip, delta) )
    1915 {
    1916 /* if variable is integral, round delta down so that it will still have an integer value */
    1917 if( SCIPvarIsIntegral(var) )
    1918 delta = SCIPfloor(scip, delta);
    1919 SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
    1920 /*lint --e{613} */
    1921 SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
    1922 SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
    1923
    1924 /* adjust constraint violation, if satisfied go on to next constraint */
    1925 viol -= consdata->linvardecrcoef * delta;
    1926 if( SCIPisZero(scip, viol) )
    1927 continue;
    1928 }
    1929 }
    1930
    1931 /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
    1932 break;
    1933 }
    1934
    1935 /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
    1936 * then pass it to the trysol heuristic
    1937 */
    1939 {
    1940 SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
    1941
    1942 assert(conshdlrdata->trysolheur != NULL);
    1943 SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
    1944
    1945 *success = TRUE;
    1946 }
    1947
    1948 SCIP_CALL( SCIPfreeSol(scip, &newsol) );
    1949
    1950 return SCIP_OKAY;
    1951}
    1952
    1953/** notify nonlinear handlers to add linearization in new solution that has been found
    1954 *
    1955 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
    1956 *
    1957 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
    1958 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
    1959 * cut that is valid and supporting in the given solution.
    1960 * For example, for convex constraints, we achieve this by linearizing.
    1961 * For SOC, we also linearize, but on a a convex reformulation.
    1962 *
    1963 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
    1964 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
    1965 */
    1966static
    1968 SCIP* scip, /**< SCIP data structure */
    1969 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    1970 SCIP_CONS** conss, /**< constraints */
    1971 int nconss, /**< number of constraints */
    1972 SCIP_SOL* sol, /**< reference point where to estimate */
    1973 SCIP_Bool solisbest /**< whether solution is best */
    1974 )
    1975{
    1976 SCIP_CONSDATA* consdata;
    1977 SCIP_Longint soltag;
    1978 SCIP_EXPRITER* it;
    1979 SCIP_EXPR* expr;
    1980 int c, e;
    1981
    1982 assert(scip != NULL);
    1983 assert(conshdlr != NULL);
    1984 assert(conss != NULL || nconss == 0);
    1985
    1986 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
    1987
    1988 /* TODO probably we just evaluated all expressions when checking the sol before it was added
    1989 * would be nice to recognize this and skip reevaluating
    1990 */
    1991 soltag = SCIPgetExprNewSoltag(scip);
    1992
    1996
    1997 for( c = 0; c < nconss; ++c )
    1998 {
    1999 /* skip constraints that are not enabled or deleted or have separation disabled */
    2000 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
    2001 continue;
    2002 assert(SCIPconsIsActive(conss[c]));
    2003
    2004 consdata = SCIPconsGetData(conss[c]);
    2005 assert(consdata != NULL);
    2006
    2007 ENFOLOG(
    2008 {
    2009 int i;
    2010 SCIPinfoMessage(scip, enfologfile, " constraint ");
    2011 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
    2012 SCIPinfoMessage(scip, enfologfile, "\n and point\n");
    2013 for( i = 0; i < consdata->nvarexprs; ++i )
    2014 {
    2015 SCIP_VAR* var;
    2016 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    2017 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
    2018 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
    2019 }
    2020 })
    2021
    2022 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
    2023 assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
    2024
    2025 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    2026 {
    2027 SCIP_EXPR_OWNERDATA* ownerdata;
    2028
    2029 ownerdata = SCIPexprGetOwnerData(expr);
    2030 assert(ownerdata != NULL);
    2031
    2032 /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
    2033 assert(SCIPexprGetEvalTag(expr) == soltag);
    2034 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
    2035 if( ownerdata->auxvar != NULL )
    2036 {
    2037 SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
    2038 }
    2039
    2040 /* let nonlinear handler generate cuts by calling the sollinearize callback */
    2041 for( e = 0; e < ownerdata->nenfos; ++e )
    2042 {
    2043 /* call sollinearize callback, if implemented by nlhdlr */
    2044 SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
    2045 ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
    2046 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
    2047 ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
    2048 }
    2049 }
    2050 }
    2051
    2052 SCIPfreeExpriter(&it);
    2053
    2054 return SCIP_OKAY;
    2055}
    2056
    2057/** processes the event that a new primal solution has been found */
    2058static
    2059SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
    2060{
    2061 SCIP_CONSHDLR* conshdlr;
    2062 SCIP_CONSHDLRDATA* conshdlrdata;
    2063 SCIP_SOL* sol;
    2064
    2065 assert(scip != NULL);
    2066 assert(event != NULL);
    2067 assert(eventdata != NULL);
    2068 assert(eventhdlr != NULL);
    2070
    2071 conshdlr = (SCIP_CONSHDLR*)eventdata;
    2072
    2073 if( SCIPconshdlrGetNConss(conshdlr) == 0 )
    2074 return SCIP_OKAY;
    2075
    2076 sol = SCIPeventGetSol(event);
    2077 assert(sol != NULL);
    2078
    2079 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2080 assert(conshdlrdata != NULL);
    2081
    2082 /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
    2083 * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
    2084 * from the tree, but postprocessed via proposeFeasibleSolution
    2085 */
    2086 if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
    2087 return SCIP_OKAY;
    2088
    2089 SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
    2090
    2092
    2093 return SCIP_OKAY;
    2094}
    2095
    2096/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
    2097 *
    2098 * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
    2099 * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
    2100 *
    2101 * Nothing will happen if SCIP is not in presolve or solve.
    2102 */
    2103static
    2105 SCIP* scip, /**< SCIP data structure */
    2106 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2107 SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
    2108 SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
    2109 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
    2110 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
    2111 )
    2112{
    2113 SCIP_VAR* var;
    2114 SCIP_Bool tightenedlb;
    2115 SCIP_Bool tightenedub;
    2116 SCIP_Bool force;
    2117
    2118 assert(scip != NULL);
    2119 assert(conshdlr != NULL);
    2120 assert(expr != NULL);
    2121 assert(cutoff != NULL);
    2122
    2123 /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
    2125
    2126 *cutoff = FALSE;
    2127
    2128 var = SCIPgetExprAuxVarNonlinear(expr);
    2129 if( var == NULL )
    2130 return SCIP_OKAY;
    2131
    2132 /* force tightening if conshdlrdata says so or it would mean fixing the variable */
    2133 force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
    2134
    2135 /* try to tighten lower bound of (auxiliary) variable */
    2136 SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
    2137 if( tightenedlb )
    2138 {
    2139 if( ntightenings != NULL )
    2140 ++*ntightenings;
    2141 SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
    2142 }
    2143 if( *cutoff )
    2144 {
    2145 SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
    2146 return SCIP_OKAY;
    2147 }
    2148
    2149 /* try to tighten upper bound of (auxiliary) variable */
    2150 SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
    2151 if( tightenedub )
    2152 {
    2153 if( ntightenings != NULL )
    2154 ++*ntightenings;
    2155 SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
    2156 }
    2157 if( *cutoff )
    2158 {
    2159 SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
    2160 return SCIP_OKAY;
    2161 }
    2162
    2163 /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
    2164 * that seems unnecessary and we could easily undo this here, e.g.,
    2165 * if( tightenedlb ) expr->activity.inf = bounds.inf
    2166 */
    2167
    2168 return SCIP_OKAY;
    2169}
    2170
    2171/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
    2172 * and tries to tighten the bounds of the auxiliary variables accordingly
    2173 */
    2174static
    2176 SCIP* scip, /**< SCIP data structure */
    2177 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2178 SCIP_EXPR* rootexpr, /**< expression */
    2179 SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
    2180 SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
    2181 int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
    2182 )
    2183{
    2184 SCIP_EXPRITER* it;
    2185 SCIP_EXPR* expr;
    2186 SCIP_EXPR_OWNERDATA* ownerdata;
    2187 SCIP_CONSHDLRDATA* conshdlrdata;
    2188
    2189 assert(scip != NULL);
    2190 assert(rootexpr != NULL);
    2191
    2192 if( infeasible != NULL )
    2193 *infeasible = FALSE;
    2194 if( ntightenings != NULL )
    2195 *ntightenings = 0;
    2196
    2197 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2198 assert(conshdlrdata != NULL);
    2199
    2200 /* if value is valid and empty, then we cannot improve, so do nothing */
    2201 if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
    2202 {
    2203 SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
    2204
    2205 if( infeasible != NULL )
    2206 *infeasible = TRUE;
    2207
    2208 /* just update tag to curboundstag */
    2209 SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
    2210
    2211 return SCIP_OKAY;
    2212 }
    2213
    2214 /* if value is up-to-date, then nothing to do */
    2215 if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
    2216 {
    2217 SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
    2218
    2219 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
    2220
    2221 return SCIP_OKAY;
    2222 }
    2223
    2224 ownerdata = SCIPexprGetOwnerData(rootexpr);
    2225 assert(ownerdata != NULL);
    2226
    2227 /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
    2228 * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
    2229 * during detect, we are in some in-between state where we may want to eval activity
    2230 * on exprs that we did not notify about their activity usage
    2231 */
    2232 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
    2233 {
    2234#ifdef DEBUG_PROP
    2235 SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
    2236#endif
    2237 SCIPABORT();
    2238 return SCIP_OKAY;
    2239 }
    2240
    2244
    2245 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
    2246 {
    2247 switch( SCIPexpriterGetStageDFS(it) )
    2248 {
    2250 {
    2251 /* skip child if it has been evaluated already */
    2252 SCIP_EXPR* child;
    2253
    2254 child = SCIPexpriterGetChildExprDFS(it);
    2255 if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
    2256 {
    2258 *infeasible = TRUE;
    2259
    2260 expr = SCIPexpriterSkipDFS(it);
    2261 continue;
    2262 }
    2263
    2264 break;
    2265 }
    2266
    2268 {
    2269 SCIP_INTERVAL activity;
    2270
    2271 /* we should not have entered this expression if its activity was already up to date */
    2272 assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
    2273
    2274 ownerdata = SCIPexprGetOwnerData(expr);
    2275 assert(ownerdata != NULL);
    2276
    2277 /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
    2278 * so we can assume that the activity is up to date for all these variables
    2279 * UNLESS we changed the method used to evaluate activity of variable expressions
    2280 * or we currently use global bounds (varevents are catched for local bound changes only)
    2281 */
    2282 if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
    2283 SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
    2284 {
    2285#ifndef NDEBUG
    2286 SCIP_INTERVAL exprhdlrinterval;
    2287
    2288 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
    2289 assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
    2290 assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
    2291#endif
    2292#ifdef DEBUG_PROP
    2293 SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
    2294#endif
    2295 SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
    2296
    2297 break;
    2298 }
    2299
    2300 if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
    2301 {
    2302 /* start with entire activity if current one is invalid */
    2304 }
    2306 {
    2307 /* If already empty, then don't try to compute even better activity.
    2308 * If cons_nonlinear were alone, then we should have noted that we are infeasible
    2309 * so an assert(infeasible == NULL || *infeasible) should work here.
    2310 * However, after reporting a cutoff due to expr->activity being empty,
    2311 * SCIP may wander to a different node and call propagation again.
    2312 * If no bounds in a nonlinear constraint have been relaxed when switching nodes
    2313 * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
    2314 * we will still have expr->activity being empty, but will have forgotten
    2315 * that we found infeasibility here before (!2221#note_134120).
    2316 * Therefore we just set *infeasibility=TRUE here and stop.
    2317 */
    2318 if( infeasible != NULL )
    2319 *infeasible = TRUE;
    2320 SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
    2321 break;
    2322 }
    2323 else
    2324 {
    2325 /* start with current activity, since it is valid */
    2326 activity = SCIPexprGetActivity(expr);
    2327 }
    2328
    2329 /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
    2330 if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
    2331 {
    2332#ifdef DEBUG_PROP
    2333 SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
    2334#endif
    2335 break;
    2336 }
    2337
    2338#ifdef DEBUG_PROP
    2339 SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
    2340 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    2341 SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
    2342#endif
    2343
    2344 /* run interval eval of nonlinear handlers or expression handler */
    2345 if( ownerdata->nenfos > 0 )
    2346 {
    2347 SCIP_NLHDLR* nlhdlr;
    2348 SCIP_INTERVAL nlhdlrinterval;
    2349 int e;
    2350
    2351 /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
    2352 for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
    2353 {
    2354 /* skip nlhdlr if it does not want to participate in activity computation */
    2355 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
    2356 continue;
    2357
    2358 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    2359 assert(nlhdlr != NULL);
    2360
    2361 /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
    2362 if( !SCIPnlhdlrHasIntEval(nlhdlr) )
    2363 continue;
    2364
    2365 /* let nlhdlr evaluate current expression */
    2366 nlhdlrinterval = activity;
    2367 SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
    2368 &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
    2369#ifdef DEBUG_PROP
    2370 SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
    2371#endif
    2372
    2373 /* update activity by intersecting with computed activity */
    2374 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
    2375#ifdef DEBUG_PROP
    2376 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
    2377#endif
    2378 }
    2379 }
    2380 else
    2381 {
    2382 /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
    2383 SCIP_INTERVAL exprhdlrinterval = activity;
    2384 SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
    2385#ifdef DEBUG_PROP
    2386 SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
    2387#endif
    2388
    2389 /* update expr->activity by intersecting with computed activity */
    2390 SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
    2391#ifdef DEBUG_PROP
    2392 SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
    2393#endif
    2394 }
    2395
    2396 /* if expression is integral, then we try to tighten the interval bounds a bit
    2397 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
    2398 * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
    2399 * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
    2400 * boundtightening-inteval does not relax integer variables, so can omit expressions without children
    2401 * (constants should be ok, too)
    2402 */
    2403 if( SCIPexprIsIntegral(expr) &&
    2404 conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
    2405 {
    2406 if( activity.inf > -SCIP_INTERVAL_INFINITY )
    2407 activity.inf = SCIPceil(scip, activity.inf);
    2408 if( activity.sup < SCIP_INTERVAL_INFINITY )
    2409 activity.sup = SCIPfloor(scip, activity.sup);
    2410#ifdef DEBUG_PROP
    2411 SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
    2412#endif
    2413 }
    2414
    2415 /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
    2416 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
    2417 */
    2418 if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
    2419 {
    2420 SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
    2421 SCIPintervalSetEmpty(&activity);
    2422 }
    2423
    2424 /* now finally store activity in expr */
    2425 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
    2426
    2428 {
    2429 if( infeasible != NULL )
    2430 *infeasible = TRUE;
    2431 }
    2432 else if( tightenauxvars && ownerdata->auxvar != NULL )
    2433 {
    2434 SCIP_Bool tighteninfeasible;
    2435
    2436 SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
    2437 if( tighteninfeasible )
    2438 {
    2439 if( infeasible != NULL )
    2440 *infeasible = TRUE;
    2441 SCIPintervalSetEmpty(&activity);
    2442 SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
    2443 }
    2444 }
    2445
    2446 break;
    2447 }
    2448
    2449 default:
    2450 /* you should never be here */
    2451 SCIPerrorMessage("unexpected iterator stage\n");
    2452 SCIPABORT();
    2453 break;
    2454 }
    2455
    2456 expr = SCIPexpriterGetNext(it);
    2457 }
    2458
    2459 SCIPfreeExpriter(&it);
    2460
    2461 return SCIP_OKAY;
    2462}
    2463
    2464/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
    2465 *
    2466 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
    2467 *
    2468 * If `subsetsufficient` is FALSE, then we require
    2469 * - a change from an unbounded interval to a bounded one, or
    2470 * - or a change from an unfixed (width > epsilon) to a fixed interval, or
    2471 * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
    2472 */
    2473static
    2475 SCIP* scip, /**< SCIP data structure */
    2476 SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
    2477 SCIP_INTERVAL newinterval, /**< new interval */
    2478 SCIP_INTERVAL oldinterval /**< old interval */
    2479 )
    2480{
    2481 assert(scip != NULL);
    2482 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
    2483 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
    2484
    2485 if( subsetsufficient )
    2486 /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
    2487 return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
    2488
    2489 /* check whether lower bound of interval becomes finite */
    2490 if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
    2491 return TRUE;
    2492
    2493 /* check whether upper bound of interval becomes finite */
    2494 if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
    2495 return TRUE;
    2496
    2497 /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
    2498 if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
    2499 return TRUE;
    2500
    2501 /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
    2502 if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
    2503 return TRUE;
    2504
    2505 /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
    2506 if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
    2507 return TRUE;
    2508
    2509 return FALSE;
    2510}
    2511
    2512/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
    2513 *
    2514 * The expression will be traversed in breadth first search by using this queue.
    2515 *
    2516 * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
    2517 * forwardPropExpr() before calling this function.
    2518 *
    2519 * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
    2520 */
    2521static
    2523 SCIP* scip, /**< SCIP data structure */
    2524 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2525 SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
    2526 int* ntightenings /**< buffer to store the number of (variable) tightenings */
    2527 )
    2528{
    2529 SCIP_CONSHDLRDATA* conshdlrdata;
    2530 SCIP_EXPR* expr;
    2531 SCIP_EXPR_OWNERDATA* ownerdata;
    2532
    2533 assert(infeasible != NULL);
    2534 assert(ntightenings != NULL);
    2535
    2536 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2537 assert(conshdlrdata != NULL);
    2538
    2539 *ntightenings = 0;
    2540
    2541 /* main loop that calls reverse propagation for expressions on the queue
    2542 * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
    2543 */
    2544 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
    2545 {
    2546 SCIP_INTERVAL propbounds;
    2547 int e;
    2548
    2549 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
    2550 assert(expr != NULL);
    2551
    2552 ownerdata = SCIPexprGetOwnerData(expr);
    2553 assert(ownerdata != NULL);
    2554
    2555 assert(ownerdata->inpropqueue);
    2556 /* mark that the expression is not in the queue anymore */
    2557 ownerdata->inpropqueue = FALSE;
    2558
    2559 /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
    2560 * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
    2561 */
    2562 assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
    2563 assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
    2564 assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
    2565
    2566 /* this intersects propbounds with activity and auxvar bounds
    2567 * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
    2568 * auxvar bounds separately, so disabling this for now
    2569 */
    2570#ifdef SCIP_DISABLED_CODE
    2571 propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
    2573 {
    2574 *infeasible = TRUE;
    2575 break;
    2576 }
    2577#else
    2578 propbounds = ownerdata->propbounds;
    2579#endif
    2580
    2581 if( ownerdata->nenfos > 0 )
    2582 {
    2583 /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
    2584 for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
    2585 {
    2586 SCIP_NLHDLR* nlhdlr;
    2587 int nreds;
    2588
    2589 /* skip nlhdlr if it does not want to participate in activity computation */
    2590 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
    2591 continue;
    2592
    2593 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    2594 assert(nlhdlr != NULL);
    2595
    2596 /* call the reverseprop of the nlhdlr */
    2597#ifdef SCIP_DEBUG
    2598 SCIPdebugMsg(scip, "call reverse propagation for ");
    2599 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    2600 SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
    2601#endif
    2602
    2603 nreds = 0;
    2604 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
    2605 assert(nreds >= 0);
    2606 *ntightenings += nreds;
    2607 }
    2608 }
    2610 {
    2611 /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
    2612 SCIP_INTERVAL* childrenbounds;
    2613 int c;
    2614
    2615#ifdef SCIP_DEBUG
    2616 SCIPdebugMsg(scip, "call reverse propagation for ");
    2617 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    2618 SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
    2619#endif
    2620
    2621 /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
    2622 * been initialized in detectNlhdlr yet (nenfos < 0)
    2623 */
    2624 assert(ownerdata->nenfos < 0);
    2625
    2626 SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
    2627 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
    2628 childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
    2629
    2630 /* call the reverseprop of the exprhdlr */
    2631 SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
    2632
    2633 if( !*infeasible )
    2634 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
    2635 {
    2636 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
    2637 }
    2638
    2639 SCIPfreeBufferArray(scip, &childrenbounds);
    2640 }
    2641 }
    2642
    2643 /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
    2644 while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
    2645 {
    2646 expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
    2647 assert(expr != NULL);
    2648
    2649 ownerdata = SCIPexprGetOwnerData(expr);
    2650 assert(ownerdata != NULL);
    2651
    2652 /* mark that the expression is not in the queue anymore */
    2653 ownerdata->inpropqueue = FALSE;
    2654 }
    2655
    2656 return SCIP_OKAY;
    2657}
    2658
    2659/** calls domain propagation for a given set of constraints
    2660 *
    2661 * The algorithm alternates calls of forward and reverse propagation.
    2662 * Forward propagation ensures that activity of expressions is up to date.
    2663 * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
    2664 * [lhs,rhs] interval as starting point.
    2665 *
    2666 * The propagation algorithm works as follows:
    2667 * 1. apply forward propagation (update activities) for all constraints not marked as propagated
    2668 * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
    2669 * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
    2670 * provide tighter bounds
    2671 * 3. apply reverse propagation to all collected expressions; don't explore
    2672 * sub-expressions which have not changed since the beginning of the propagation loop
    2673 * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
    2674 *
    2675 * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
    2676 * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
    2677 * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
    2678 *
    2679 * TODO should we distinguish between expressions where activity information is used for separation and those where not,
    2680 * e.g., try less to propagate on convex constraints?
    2681 */
    2682static
    2684 SCIP* scip, /**< SCIP data structure */
    2685 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2686 SCIP_CONS** conss, /**< constraints to propagate */
    2687 int nconss, /**< total number of constraints */
    2688 SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
    2689 SCIP_RESULT* result, /**< pointer to store the result */
    2690 int* nchgbds /**< buffer to add the number of changed bounds */
    2691 )
    2692{
    2693 SCIP_CONSHDLRDATA* conshdlrdata;
    2694 SCIP_CONSDATA* consdata;
    2695 SCIP_EXPR_OWNERDATA* ownerdata;
    2696 SCIP_Bool cutoff = FALSE;
    2697 SCIP_INTERVAL conssides;
    2698 int ntightenings;
    2699 int roundnr;
    2700 SCIP_EXPRITER* revpropcollectit = NULL;
    2701 int i;
    2702
    2703 assert(scip != NULL);
    2704 assert(conshdlr != NULL);
    2705 assert(conss != NULL);
    2706 assert(nconss >= 0);
    2707 assert(result != NULL);
    2708 assert(nchgbds != NULL);
    2709 assert(*nchgbds >= 0);
    2710
    2711 /* no constraints to propagate */
    2712 if( nconss == 0 )
    2713 {
    2714 *result = SCIP_DIDNOTRUN;
    2715 return SCIP_OKAY;
    2716 }
    2717
    2718 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    2719 assert(conshdlrdata != NULL);
    2720#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
    2721 assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
    2722#endif
    2723 assert(!conshdlrdata->globalbounds);
    2724
    2725 *result = SCIP_DIDNOTFIND;
    2726 roundnr = 0;
    2727
    2728 /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
    2729 conshdlrdata->forceboundtightening = force;
    2730
    2731 /* invalidate all propbounds (probably not needed) */
    2732 ++conshdlrdata->curpropboundstag;
    2733
    2734 /* create iterator that we will use if we need to look at all auxvars */
    2735 if( conshdlrdata->propauxvars )
    2736 {
    2737 SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
    2738 }
    2739
    2740 /* main propagation loop */
    2741 do
    2742 {
    2743 SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
    2744
    2745 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
    2746
    2747 /* apply forward propagation (update expression activities)
    2748 * and add promising root expressions into queue for reversepropagation
    2749 */
    2750 for( i = 0; i < nconss; ++i )
    2751 {
    2752 consdata = SCIPconsGetData(conss[i]);
    2753 assert(consdata != NULL);
    2754
    2755 /* skip deleted, non-active, or propagation-disabled constraints */
    2756 if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
    2757 continue;
    2758
    2759 /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
    2760 * activity didn't change
    2761 */
    2762 if( consdata->ispropagated )
    2763 continue;
    2764
    2765 /* update activities in expression */
    2766 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
    2767 SCIPdebugPrintCons(scip, conss[i], NULL);
    2768
    2769 ntightenings = 0;
    2770 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
    2771 assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
    2772
    2773 if( cutoff )
    2774 {
    2775 SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
    2776 *result = SCIP_CUTOFF;
    2777 break;
    2778 }
    2779
    2780 ownerdata = SCIPexprGetOwnerData(consdata->expr);
    2781
    2782 /* 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 */
    2783 if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
    2784 {
    2785 /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
    2786 * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
    2787 * so taking auxvar bounds is enough)
    2788 */
    2789 if( ownerdata->auxvar == NULL )
    2790 {
    2791 /* relax sides by SCIPepsilon() and handle infinite sides */
    2792 SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
    2793 SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
    2794 SCIPintervalSetBounds(&conssides, lhs, rhs);
    2795 }
    2796 else
    2797 {
    2798 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
    2799 }
    2800 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
    2801 }
    2802 else
    2803 {
    2804 /* check whether bounds of any auxvar used in constraint provides a tightening
    2805 * (for the root expression, bounds of auxvar are initially set to constraint sides)
    2806 * but skip exprs that have an auxvar, but do not participate in propagation
    2807 */
    2808 SCIP_EXPR* expr;
    2809
    2810 assert(revpropcollectit != NULL);
    2811 SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
    2812 for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
    2813 {
    2814 ownerdata = SCIPexprGetOwnerData(expr);
    2815 assert(ownerdata != NULL);
    2816
    2817 if( ownerdata->auxvar == NULL )
    2818 continue;
    2819
    2820 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
    2821 continue;
    2822
    2823 conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
    2824 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
    2825 }
    2826 }
    2827
    2828 if( cutoff )
    2829 {
    2830 SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
    2831 *result = SCIP_CUTOFF;
    2832 break;
    2833 }
    2834
    2835 assert(ntightenings >= 0);
    2836 if( ntightenings > 0 )
    2837 {
    2838 *nchgbds += ntightenings;
    2839 *result = SCIP_REDUCEDDOM;
    2840 }
    2841
    2842 /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
    2843 consdata->ispropagated = TRUE;
    2844 }
    2845
    2846 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
    2847 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
    2848 assert(ntightenings >= 0);
    2849 assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
    2850
    2851 if( cutoff )
    2852 {
    2853 SCIPdebugMsg(scip, " -> cutoff\n");
    2854 *result = SCIP_CUTOFF;
    2855 break;
    2856 }
    2857
    2858 if( ntightenings > 0 )
    2859 {
    2860 *nchgbds += ntightenings;
    2861 *result = SCIP_REDUCEDDOM;
    2862 }
    2863 }
    2864 while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
    2865
    2866 if( conshdlrdata->propauxvars )
    2867 {
    2868 SCIPfreeExpriter(&revpropcollectit);
    2869 }
    2870
    2871 conshdlrdata->forceboundtightening = FALSE;
    2872
    2873 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
    2874 ++conshdlrdata->curpropboundstag;
    2875
    2876 return SCIP_OKAY;
    2877}
    2878
    2879/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
    2880 *
    2881 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
    2882 *
    2883 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
    2884 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
    2885 */
    2886static
    2888 SCIP* scip, /**< SCIP data structure */
    2889 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    2890 SCIP_CONS** conss, /**< constraints to propagate */
    2891 int nconss, /**< total number of constraints */
    2892 SCIP_RESULT* result, /**< pointer to store the result */
    2893 int* nchgbds /**< buffer to add the number of changed bounds */
    2894 )
    2895{
    2896 SCIP_CONSDATA* consdata;
    2897 SCIP_EXPRITER* it;
    2898 SCIP_EXPR* expr;
    2899 SCIP_EXPR_OWNERDATA* ownerdata;
    2900 SCIP_Bool cutoff = FALSE;
    2901 int ntightenings;
    2902 int c;
    2903 int e;
    2904
    2905 assert(scip != NULL);
    2906 assert(conshdlr != NULL);
    2907 assert(conss != NULL);
    2908 assert(nconss >= 0);
    2909 assert(result != NULL);
    2910 assert(nchgbds != NULL);
    2911 assert(*nchgbds >= 0);
    2912
    2913#ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
    2914 assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
    2915#endif
    2916 assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
    2917 assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
    2918
    2919 *result = SCIP_DIDNOTFIND;
    2920
    2923
    2924 for( c = 0; c < nconss && !cutoff; ++c )
    2925 {
    2926 /* skip deleted, non-active, or propagation-disabled constraints */
    2927 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
    2928 continue;
    2929
    2930 consdata = SCIPconsGetData(conss[c]);
    2931 assert(consdata != NULL);
    2932
    2933 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
    2934 {
    2935 ownerdata = SCIPexprGetOwnerData(expr);
    2936 assert(ownerdata != NULL);
    2937
    2938 /* call reverseprop for those nlhdlr that participate in this expr's activity computation
    2939 * this will propagate the current activity
    2940 */
    2941 for( e = 0; e < ownerdata->nenfos; ++e )
    2942 {
    2943 SCIP_NLHDLR* nlhdlr;
    2944 assert(ownerdata->enfos[e] != NULL);
    2945
    2946 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    2947 assert(nlhdlr != NULL);
    2948 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
    2949 continue;
    2950
    2951 SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
    2952 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
    2953 ntightenings = 0;
    2954 SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
    2955 SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
    2956
    2957 if( cutoff )
    2958 {
    2959 /* stop everything if we detected infeasibility */
    2960 SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
    2961 *result = SCIP_CUTOFF;
    2962 break;
    2963 }
    2964
    2965 assert(ntightenings >= 0);
    2966 if( ntightenings > 0 )
    2967 {
    2968 *nchgbds += ntightenings;
    2969 *result = SCIP_REDUCEDDOM;
    2970 }
    2971 }
    2972 }
    2973 }
    2974
    2975 /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
    2976 SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
    2977 assert(ntightenings >= 0);
    2978
    2979 if( cutoff )
    2980 {
    2981 SCIPdebugMsg(scip, " -> cutoff\n");
    2982 *result = SCIP_CUTOFF;
    2983 }
    2984 else if( ntightenings > 0 )
    2985 {
    2986 *nchgbds += ntightenings;
    2987 *result = SCIP_REDUCEDDOM;
    2988 }
    2989
    2990 SCIPfreeExpriter(&it);
    2991
    2992 /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
    2993 ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
    2994
    2995 return SCIP_OKAY;
    2996}
    2997
    2998/** propagates variable locks through expression and adds locks to variables */
    2999static
    3001 SCIP* scip, /**< SCIP data structure */
    3002 SCIP_EXPR* expr, /**< expression */
    3003 int nlockspos, /**< number of positive locks */
    3004 int nlocksneg /**< number of negative locks */
    3005 )
    3006{
    3007 SCIP_EXPR_OWNERDATA* ownerdata;
    3008 SCIP_EXPRITER* it;
    3009 SCIP_EXPRITER_USERDATA ituserdata;
    3010
    3011 assert(expr != NULL);
    3012
    3013 /* if no locks, then nothing to propagate */
    3014 if( nlockspos == 0 && nlocksneg == 0 )
    3015 return SCIP_OKAY;
    3016
    3020 assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
    3021
    3022 /* store locks in root node */
    3023 ituserdata.intvals[0] = nlockspos;
    3024 ituserdata.intvals[1] = nlocksneg;
    3025 SCIPexpriterSetCurrentUserData(it, ituserdata);
    3026
    3027 while( !SCIPexpriterIsEnd(it) )
    3028 {
    3029 /* collect locks */
    3030 ituserdata = SCIPexpriterGetCurrentUserData(it);
    3031 nlockspos = ituserdata.intvals[0];
    3032 nlocksneg = ituserdata.intvals[1];
    3033
    3034 ownerdata = SCIPexprGetOwnerData(expr);
    3035
    3036 switch( SCIPexpriterGetStageDFS(it) )
    3037 {
    3039 {
    3040 if( SCIPisExprVar(scip, expr) )
    3041 {
    3042 /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
    3043 SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
    3044 }
    3045
    3046 /* add locks to expression */
    3047 ownerdata->nlockspos += nlockspos;
    3048 ownerdata->nlocksneg += nlocksneg;
    3049
    3050 /* add monotonicity information if expression has been locked for the first time */
    3051 if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
    3053 {
    3054 int i;
    3055
    3056 assert(ownerdata->monotonicity == NULL);
    3057 assert(ownerdata->monotonicitysize == 0);
    3058
    3059 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
    3060 ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
    3061
    3062 /* store the monotonicity for each child */
    3063 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
    3064 {
    3065 SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
    3066 }
    3067 }
    3068 break;
    3069 }
    3070
    3072 {
    3073 /* remove monotonicity information if expression has been unlocked */
    3074 if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
    3075 {
    3076 assert(ownerdata->monotonicitysize > 0);
    3077 /* keep this assert for checking whether someone changed an expression without updating locks properly */
    3078 assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
    3079
    3080 SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
    3081 ownerdata->monotonicitysize = 0;
    3082 }
    3083 break;
    3084 }
    3085
    3087 {
    3088 SCIP_MONOTONE monotonicity;
    3089
    3090 /* get monotonicity of child */
    3091 /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
    3092 * SCIPcallExprMonotonicity
    3093 */
    3094 monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
    3095
    3096 /* compute resulting locks of the child expression */
    3097 switch( monotonicity )
    3098 {
    3099 case SCIP_MONOTONE_INC:
    3100 ituserdata.intvals[0] = nlockspos;
    3101 ituserdata.intvals[1] = nlocksneg;
    3102 break;
    3103 case SCIP_MONOTONE_DEC:
    3104 ituserdata.intvals[0] = nlocksneg;
    3105 ituserdata.intvals[1] = nlockspos;
    3106 break;
    3108 ituserdata.intvals[0] = nlockspos + nlocksneg;
    3109 ituserdata.intvals[1] = nlockspos + nlocksneg;
    3110 break;
    3112 ituserdata.intvals[0] = 0;
    3113 ituserdata.intvals[1] = 0;
    3114 break;
    3115 }
    3116 /* set locks in child expression */
    3117 SCIPexpriterSetChildUserData(it, ituserdata);
    3118
    3119 break;
    3120 }
    3121
    3122 default :
    3123 /* you should never be here */
    3124 SCIPABORT();
    3125 break;
    3126 }
    3127
    3128 expr = SCIPexpriterGetNext(it);
    3129 }
    3130
    3131 SCIPfreeExpriter(&it);
    3132
    3133 return SCIP_OKAY;
    3134}
    3135
    3136/** main function for adding locks to expressions and variables
    3137 *
    3138 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
    3139 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
    3140 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
    3141 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
    3142 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
    3143 * the computed monotonicity information of each expression until all locks of an expression have been removed,
    3144 * which implies that updating the monotonicity information during the next locking of this expression does not
    3145 * break existing locks.
    3146 *
    3147 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
    3148 * locks from an expression and repropagating them after the structural changes have been applied.
    3149 * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
    3150 * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
    3151 */
    3152static
    3154 SCIP* scip, /**< SCIP data structure */
    3155 SCIP_CONS* cons, /**< nonlinear constraint */
    3156 int nlockspos, /**< number of positive rounding locks */
    3157 int nlocksneg /**< number of negative rounding locks */
    3158 )
    3159{
    3160 SCIP_CONSDATA* consdata;
    3161
    3162 assert(cons != NULL);
    3163
    3164 if( nlockspos == 0 && nlocksneg == 0 )
    3165 return SCIP_OKAY;
    3166
    3167 consdata = SCIPconsGetData(cons);
    3168 assert(consdata != NULL);
    3169
    3170 /* no constraint sides -> nothing to lock */
    3171 if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
    3172 return SCIP_OKAY;
    3173
    3174 /* remember locks */
    3175 consdata->nlockspos += nlockspos;
    3176 consdata->nlocksneg += nlocksneg;
    3177
    3178 assert(consdata->nlockspos >= 0);
    3179 assert(consdata->nlocksneg >= 0);
    3180
    3181 /* compute locks for lock propagation */
    3182 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
    3183 {
    3184 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg) );
    3185 }
    3186 else if( !SCIPisInfinity(scip, consdata->rhs) )
    3187 {
    3188 SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg) );
    3189 }
    3190 else
    3191 {
    3192 assert(!SCIPisInfinity(scip, -consdata->lhs));
    3193 SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos) );
    3194 }
    3195
    3196 return SCIP_OKAY;
    3197}
    3198
    3199/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
    3200static
    3202 SCIP* scip, /**< SCIP data structure */
    3203 SCIP_CONS* cons /**< nonlinear constraint */
    3204 )
    3205{
    3206 SCIP_CONSDATA* consdata;
    3207
    3208 assert(scip != NULL);
    3209 assert(cons != NULL);
    3210
    3211 consdata = SCIPconsGetData(cons);
    3212 assert(consdata != NULL);
    3213 assert(consdata->expr != NULL);
    3214
    3215 if( consdata->nlrow != NULL )
    3216 {
    3217 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
    3218 }
    3219
    3220 /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
    3221 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
    3222 0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
    3223
    3224 if( SCIPisExprSum(scip, consdata->expr) )
    3225 {
    3226 /* if root is a sum, then split into linear and nonlinear terms */
    3227 SCIP_EXPR* nonlinpart;
    3228 SCIP_EXPR* child;
    3229 SCIP_Real* coefs;
    3230 int i;
    3231
    3232 coefs = SCIPgetCoefsExprSum(consdata->expr);
    3233
    3234 /* constant term of sum */
    3235 SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
    3236
    3237 /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
    3238 SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
    3239
    3240 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
    3241 {
    3242 child = SCIPexprGetChildren(consdata->expr)[i];
    3243 if( SCIPisExprVar(scip, child) )
    3244 {
    3245 /* linear term */
    3246 SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
    3247 }
    3248 else
    3249 {
    3250 /* nonlinear term */
    3251 SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
    3252 }
    3253 }
    3254
    3255 if( SCIPexprGetNChildren(nonlinpart) > 0 )
    3256 {
    3257 /* add expression to nlrow (this will make a copy) */
    3258 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
    3259 }
    3260 SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
    3261 }
    3262 else
    3263 {
    3264 SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
    3265 }
    3266
    3267 return SCIP_OKAY;
    3268}
    3269
    3270/** compares enfodata by enforcement priority of nonlinear handler
    3271 *
    3272 * If handlers have same enforcement priority, then compare by detection priority, then by name.
    3273 */
    3274static
    3276{
    3277 SCIP_NLHDLR* h1;
    3278 SCIP_NLHDLR* h2;
    3279
    3280 assert(elem1 != NULL);
    3281 assert(elem2 != NULL);
    3282
    3283 h1 = ((EXPRENFO*)elem1)->nlhdlr;
    3284 h2 = ((EXPRENFO*)elem2)->nlhdlr;
    3285
    3286 assert(h1 != NULL);
    3287 assert(h2 != NULL);
    3288
    3291
    3294
    3295 return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
    3296}
    3297
    3298/** install nlhdlrs in one expression */
    3299static
    3301 SCIP* scip, /**< SCIP data structure */
    3302 SCIP_EXPR* expr, /**< expression for which to run detection routines */
    3303 SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
    3304 )
    3305{
    3306 SCIP_EXPR_OWNERDATA* ownerdata;
    3307 SCIP_CONSHDLRDATA* conshdlrdata;
    3308 SCIP_NLHDLR_METHOD enforcemethodsallowed;
    3309 SCIP_NLHDLR_METHOD enforcemethods;
    3310 SCIP_NLHDLR_METHOD enforcemethodsnew;
    3311 SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
    3312 SCIP_NLHDLR_METHOD nlhdlrparticipating;
    3313 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
    3314 int enfossize; /* allocated length of expr->enfos array */
    3315 int h;
    3316
    3317 assert(expr != NULL);
    3318
    3319 ownerdata = SCIPexprGetOwnerData(expr);
    3320 assert(ownerdata != NULL);
    3321
    3322 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    3323 assert(conshdlrdata != NULL);
    3324 assert(conshdlrdata->auxvarid >= 0);
    3325 assert(!conshdlrdata->indetect);
    3326
    3327 /* there should be no enforcer yet and detection should not even have considered expr yet */
    3328 assert(ownerdata->nenfos < 0);
    3329 assert(ownerdata->enfos == NULL);
    3330
    3331 /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
    3332 * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
    3333 * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
    3334 * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
    3335 * - if no one uses activity, then do not need activity methods
    3336 */
    3337 enforcemethods = SCIP_NLHDLR_METHOD_NONE;
    3338 if( ownerdata->nauxvaruses == 0 )
    3339 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
    3340 else
    3341 {
    3342 if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
    3343 enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
    3344 if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
    3345 enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
    3346 }
    3347 if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
    3348 enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
    3349
    3350 /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
    3351 assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
    3352
    3353 /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
    3354 enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
    3355
    3356 ownerdata->nenfos = 0;
    3357 enfossize = 2;
    3358 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
    3359 conshdlrdata->indetect = TRUE;
    3360
    3361 SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
    3362 cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
    3363 (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
    3364 (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
    3365 (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
    3366
    3367 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
    3368 {
    3369 SCIP_NLHDLR* nlhdlr;
    3370
    3371 nlhdlr = conshdlrdata->nlhdlrs[h];
    3372 assert(nlhdlr != NULL);
    3373
    3374 /* skip disabled nlhdlrs */
    3375 if( !SCIPnlhdlrIsEnabled(nlhdlr) )
    3376 continue;
    3377
    3378 /* call detect routine of nlhdlr */
    3379 nlhdlrexprdata = NULL;
    3380 enforcemethodsnew = enforcemethods;
    3381 nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
    3382 conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
    3383 conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
    3384 /* coverity[var_deref_model] */
    3385 SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
    3386
    3387 /* nlhdlr might have claimed more than needed: clean up sepa flags */
    3388 nlhdlrparticipating &= enforcemethodsallowed;
    3389
    3390 /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
    3391 assert((enforcemethodsnew & enforcemethods) == enforcemethods);
    3392
    3393 /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
    3394 * They are also cleaned up here to ensure that only the needed methods are claimed.
    3395 */
    3396 nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
    3397
    3398 /* nlhdlr needs to participate for the methods it is enforcing */
    3399 assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
    3400
    3401 if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
    3402 {
    3403 /* nlhdlr might not have detected anything, or all set flags might have been removed by
    3404 * clean up; in the latter case, we may need to free nlhdlrexprdata */
    3405
    3406 /* free nlhdlr exprdata, if there is any and there is a method to free this data */
    3407 if( nlhdlrexprdata != NULL )
    3408 {
    3409 SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
    3410 }
    3411 /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
    3412 assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
    3413
    3414 SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
    3415
    3416 continue;
    3417 }
    3418
    3419 SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
    3420 SCIPnlhdlrGetName(nlhdlr),
    3421 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
    3422 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
    3423 ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
    3424
    3425 /* store nlhdlr and its data */
    3426 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
    3427 SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
    3428 ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
    3429 ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
    3430 ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
    3431 ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
    3432 ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
    3433 ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
    3434 ownerdata->nenfos++;
    3435
    3436 /* update enforcement flags */
    3437 enforcemethods = enforcemethodsnew;
    3438 }
    3439
    3440 conshdlrdata->indetect = FALSE;
    3441
    3442 /* stop if an enforcement method is missing but we are already in solving stage
    3443 * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
    3444 */
    3445 if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
    3446 {
    3447 SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
    3448 return SCIP_ERROR;
    3449 }
    3450
    3451 assert(ownerdata->nenfos > 0);
    3452
    3453 /* sort nonlinear handlers by enforcement priority, in decreasing order */
    3454 if( ownerdata->nenfos > 1 )
    3455 SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
    3456
    3457 /* resize enfos array to be nenfos long */
    3458 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
    3459
    3460 return SCIP_OKAY;
    3461}
    3462
    3463/** detect nlhdlrs that can handle the expressions */
    3464static
    3466 SCIP* scip, /**< SCIP data structure */
    3467 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    3468 SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
    3469 int nconss /**< total number of constraints */
    3470 )
    3471{
    3472 SCIP_CONSHDLRDATA* conshdlrdata;
    3473 SCIP_CONSDATA* consdata;
    3474 SCIP_EXPR* expr;
    3475 SCIP_EXPR_OWNERDATA* ownerdata;
    3476 SCIP_EXPRITER* it;
    3477 int i;
    3478
    3479 assert(conss != NULL || nconss == 0);
    3480 assert(nconss >= 0);
    3481 assert(SCIPgetStage(scip) >= SCIP_STAGE_PRESOLVING && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING); /* should only be called in presolve or initsolve or consactive */
    3482
    3483 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    3484 assert(conshdlrdata != NULL);
    3485
    3488
    3490 {
    3491 /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
    3492 * for example, this happens if globally valid nonlinear constraints are added during the tree search
    3493 */
    3495 conshdlrdata->globalbounds = TRUE;
    3496 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
    3497 }
    3498
    3499 for( i = 0; i < nconss; ++i )
    3500 {
    3501 assert(conss != NULL && conss[i] != NULL);
    3502
    3503 consdata = SCIPconsGetData(conss[i]);
    3504 assert(consdata != NULL);
    3505 assert(consdata->expr != NULL);
    3506
    3507 /* if a constraint is separated, we currently need it to be initial, too
    3508 * this is because INITLP will create the auxiliary variables that are used for any separation
    3509 * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
    3510 */
    3511 assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
    3512
    3513 ownerdata = SCIPexprGetOwnerData(consdata->expr);
    3514 assert(ownerdata != NULL);
    3515
    3516 /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
    3517 * then we would normally skip to run DETECT again
    3518 * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
    3519 * thus, if expr is the root expression, we rerun DETECT
    3520 */
    3521 if( ownerdata->nenfos > 0 )
    3522 {
    3523 SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
    3524 assert(ownerdata->nenfos < 0);
    3525 }
    3526
    3527 /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
    3528 * this way we can treat the root expression like any other expression when enforcing via separation
    3529 * if constraint will be propagated, then register activity usage of root expression
    3530 * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
    3531 */
    3532 conshdlrdata->indetect = TRUE;
    3535 SCIPconsIsPropagated(conss[i]),
    3536 FALSE, FALSE) );
    3537 conshdlrdata->indetect = FALSE;
    3538
    3539 /* 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
    3540 * if this presolver may be run in the current presolve round (presoltiming=exhaustive could be added as additional criterion),
    3541 * then we ensure that a routine will be present to compute this activity (SCIPregisterExprUsageNonlinear actually updates activity already)
    3542 */
    3543 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd'
    3544 && (SCIPisInfinity(scip, -consdata->lhs) || SCIPisInfinity(scip, consdata->rhs)) && SCIPisExprSum(scip, consdata->expr) )
    3545 {
    3546 int c;
    3547 for( c = 0; c < SCIPexprGetNChildren(consdata->expr); ++c )
    3548 {
    3549 expr = SCIPexprGetChildren(consdata->expr)[c];
    3550 if( SCIPisExprProduct(scip, expr) )
    3551 {
    3553 }
    3554 }
    3555 }
    3556
    3557 /* compute integrality information for all subexpressions */
    3558 SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
    3559
    3560 /* run detectNlhdlr on all expr where required */
    3561 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    3562 {
    3563 ownerdata = SCIPexprGetOwnerData(expr);
    3564 assert(ownerdata != NULL);
    3565
    3566 /* skip exprs that we already looked at */
    3567 if( ownerdata->nenfos >= 0 )
    3568 continue;
    3569
    3570 /* if there is use of the auxvar, then someone requires that
    3571 * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
    3572 * thus, we need to find nlhdlrs that separate or estimate
    3573 * if there is use of the activity, then there is someone requiring that
    3574 * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
    3575 * thus, we need to find nlhdlrs that do interval-evaluation
    3576 */
    3577 if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
    3578 {
    3579 SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
    3580
    3581 assert(ownerdata->nenfos >= 0);
    3582 }
    3583 else
    3584 {
    3585 /* remember that we looked at this expression during detectNlhdlrs
    3586 * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
    3587 * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
    3588 * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
    3589 */
    3590 ownerdata->nenfos = 0;
    3591 }
    3592 }
    3593
    3594 /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
    3595 if( SCIPconsIsPropagated(conss[i]) )
    3596 consdata->ispropagated = FALSE;
    3597 }
    3598
    3600 {
    3601 /* ensure that the local bounds are used again when reevaluating the expressions later;
    3602 * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
    3603 */
    3605 conshdlrdata->globalbounds = FALSE;
    3606 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
    3607 }
    3608 else
    3609 {
    3610 /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
    3612 }
    3613
    3614 SCIPfreeExpriter(&it);
    3615
    3616 return SCIP_OKAY;
    3617}
    3618
    3619/** initializes (pre)solving data of constraints
    3620 *
    3621 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
    3622 * not be modified.
    3623 * In particular, this function
    3624 * - runs the detection method of nlhldrs
    3625 * - looks for unlocked linear variables
    3626 * - checks curvature (if not in presolve)
    3627 * - creates and add row to NLP (if not in presolve)
    3628 *
    3629 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
    3630 * e.g., it should be called in INITSOL and for constraints that are added during solve.
    3631 */
    3632static
    3634 SCIP* scip, /**< SCIP data structure */
    3635 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    3636 SCIP_CONS** conss, /**< constraints */
    3637 int nconss /**< number of constraints */
    3638 )
    3639{
    3640 int c;
    3641
    3642 for( c = 0; c < nconss; ++c )
    3643 {
    3644 /* check for a linear variable that can be increase or decreased without harming feasibility */
    3645 findUnlockedLinearVar(scip, conss[c]);
    3646
    3648 {
    3649 SCIP_CONSDATA* consdata;
    3650 SCIP_Bool success = FALSE;
    3651
    3652 consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
    3653 assert(consdata != NULL);
    3654 assert(consdata->expr != NULL);
    3655
    3656 if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
    3657 {
    3658 /* call the curvature detection algorithm of the convex nonlinear handler
    3659 * Check only for those curvature that may result in a convex inequality, i.e.,
    3660 * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
    3661 * Also we can assume that we are nonlinear, so do not check for convex if already concave.
    3662 */
    3663 if( !SCIPisInfinity(scip, -consdata->lhs) )
    3664 {
    3665 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
    3666 if( success )
    3667 consdata->curv = SCIP_EXPRCURV_CONCAVE;
    3668 }
    3669 if( !success && !SCIPisInfinity(scip, consdata->rhs) )
    3670 {
    3671 SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
    3672 if( success )
    3673 consdata->curv = SCIP_EXPRCURV_CONVEX;
    3674 }
    3675 }
    3676 else
    3677 {
    3678 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
    3679 {
    3680 SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
    3681 consdata->curv = SCIP_EXPRCURV_LINEAR;
    3682 }
    3683 else
    3684 {
    3685 consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
    3686 }
    3687 }
    3688 SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
    3689
    3690 /* add nlrow representation to NLP, if NLP had been constructed */
    3691 if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
    3692 {
    3693 if( consdata->nlrow == NULL )
    3694 {
    3695 SCIP_CALL( createNlRow(scip, conss[c]) );
    3696 assert(consdata->nlrow != NULL);
    3697 }
    3698 SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
    3699 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
    3700 }
    3701 }
    3702 }
    3703
    3704 /* register non linear handlers */
    3705 SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
    3706
    3707 return SCIP_OKAY;
    3708}
    3709
    3710/** deinitializes (pre)solving data of constraints
    3711 *
    3712 * This removes the initialization data created in initSolve().
    3713 *
    3714 * This function can be called in presolve and solve.
    3715 *
    3716 * TODO At the moment, it should not be called for a constraint if there are other constraints
    3717 * that use the same expressions but still require their nlhdlr.
    3718 * We should probably only decrement the auxvar and activity usage for the root expr and then
    3719 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
    3720 */
    3721static
    3723 SCIP* scip, /**< SCIP data structure */
    3724 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    3725 SCIP_CONS** conss, /**< constraints */
    3726 int nconss /**< number of constraints */
    3727 )
    3728{
    3729 SCIP_EXPRITER* it;
    3730 SCIP_EXPR* expr;
    3731 SCIP_CONSDATA* consdata;
    3732 SCIP_Bool rootactivityvalid;
    3733 int c;
    3734
    3738
    3739 /* call deinitialization callbacks of expression and nonlinear handlers
    3740 * free nonlinear handlers information from expressions
    3741 * remove auxiliary variables and nactivityuses counts from expressions
    3742 */
    3743 for( c = 0; c < nconss; ++c )
    3744 {
    3745 assert(conss != NULL);
    3746 assert(conss[c] != NULL);
    3747
    3748 consdata = SCIPconsGetData(conss[c]);
    3749 assert(consdata != NULL);
    3750 assert(consdata->expr != NULL);
    3751
    3752 /* check and remember whether activity in root is valid */
    3753 rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
    3754
    3755 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    3756 {
    3757 SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
    3758
    3759 /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
    3760 SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
    3761
    3762 /* remove quadratic info */
    3764
    3765 if( rootactivityvalid )
    3766 {
    3767 /* ensure activity is valid if consdata->expr activity is valid
    3768 * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
    3769 * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
    3770 * so this childs activity would be invalid, which can generate confusion
    3771 */
    3773 }
    3774 }
    3775
    3776 if( consdata->nlrow != NULL )
    3777 {
    3778 /* remove row from NLP, if still in solving
    3779 * if we are in exitsolve, the whole NLP will be freed anyway
    3780 */
    3782 {
    3783 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
    3784 }
    3785
    3786 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
    3787 }
    3788
    3789 /* forget about linear variables that can be increased or decreased without harming feasibility */
    3790 consdata->linvardecr = NULL;
    3791 consdata->linvarincr = NULL;
    3792
    3793 /* forget about curvature */
    3794 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
    3795 }
    3796
    3797 SCIPfreeExpriter(&it);
    3798
    3799 return SCIP_OKAY;
    3800}
    3801
    3802/** helper method to decide whether a given expression is product of at least two binary variables */
    3803static
    3805 SCIP* scip, /**< SCIP data structure */
    3806 SCIP_EXPR* expr /**< expression */
    3807 )
    3808{
    3809 int i;
    3810
    3811 assert(expr != NULL);
    3812
    3813 /* check whether the expression is a product */
    3814 if( !SCIPisExprProduct(scip, expr) )
    3815 return FALSE;
    3816
    3817 /* don't consider products with a coefficient != 1 and products with a single child
    3818 * simplification will take care of this expression later
    3819 */
    3820 if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
    3821 return FALSE;
    3822
    3823 for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
    3824 {
    3825 SCIP_EXPR* child;
    3826 SCIP_VAR* var;
    3827
    3828 child = SCIPexprGetChildren(expr)[i];
    3829 assert(child != NULL);
    3830
    3831 if( !SCIPisExprVar(scip, child) )
    3832 return FALSE;
    3833
    3834 var = SCIPgetVarExprVar(child);
    3835
    3836 /* check whether variable is binary, in any feasible solution
    3837 * we need to forbid weakly implied binary variables because cons_and wouldn't ensure that the
    3838 * product condition holds in any feasible solution (i.e., when vars may not be at bounds) in this case,
    3839 * which would lead to accepting solutions that are not feasible in the original (non-reformulated) cons
    3840 */
    3842 return FALSE;
    3843 }
    3844
    3845 return TRUE;
    3846}
    3847
    3848/** helper method to collect all bilinear binary product terms */
    3849static
    3851 SCIP* scip, /**< SCIP data structure */
    3852 SCIP_EXPR* sumexpr, /**< sum expression */
    3853 SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
    3854 SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
    3855 int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
    3856 int* nterms /**< pointer to store the total number of bilinear binary terms */
    3857 )
    3858{
    3859 int i;
    3860
    3861 assert(sumexpr != NULL);
    3862 assert(SCIPisExprSum(scip, sumexpr));
    3863 assert(xs != NULL);
    3864 assert(ys != NULL);
    3865 assert(childidxs != NULL);
    3866 assert(nterms != NULL);
    3867
    3868 *nterms = 0;
    3869
    3870 for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
    3871 {
    3872 SCIP_EXPR* child;
    3873
    3874 child = SCIPexprGetChildren(sumexpr)[i];
    3875 assert(child != NULL);
    3876
    3877 if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
    3878 {
    3881
    3882 assert(x != NULL);
    3883 assert(y != NULL);
    3884
    3885 if( x != y )
    3886 {
    3887 xs[*nterms] = x;
    3888 ys[*nterms] = y;
    3889 childidxs[*nterms] = i;
    3890 ++(*nterms);
    3891 }
    3892 }
    3893 }
    3894
    3895 return SCIP_OKAY;
    3896}
    3897
    3898/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
    3899static
    3901 SCIP* scip, /**< SCIP data structure */
    3902 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    3903 SCIP_CONS* cons, /**< constraint */
    3904 SCIP_VAR* facvar, /**< variable that has been factorized */
    3905 SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
    3906 SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
    3907 int nvars, /**< total number of variables in sum_j c_ij x_j */
    3908 SCIP_EXPR** newexpr, /**< pointer to store the new expression */
    3909 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
    3910 )
    3911{
    3912 SCIP_VAR* auxvar;
    3913 SCIP_CONS* newcons;
    3914 SCIP_Real minact = 0.0;
    3915 SCIP_Real maxact = 0.0;
    3917 char name [SCIP_MAXSTRLEN];
    3918 int i;
    3919
    3920 assert(facvar != NULL);
    3921 assert(vars != NULL);
    3922 assert(nvars > 1);
    3923 assert(newexpr != NULL);
    3924
    3925 /* compute minimum and maximum activity of sum_j c_ij x_j */
    3926 /* 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 */
    3927 for( i = 0; i < nvars; ++i )
    3928 {
    3929 minact += MIN(coefs[i], 0.0);
    3930 maxact += MAX(coefs[i], 0.0);
    3931 assert(SCIPvarIsIntegral(vars[i]));
    3933
    3934 if( impltype != SCIP_IMPLINTTYPE_NONE && !SCIPisIntegral(scip, coefs[i]) )
    3935 impltype = SCIP_IMPLINTTYPE_NONE;
    3936 }
    3937 assert(minact <= maxact);
    3938
    3939 /* create and add auxiliary variable */
    3940 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    3941 SCIP_CALL( SCIPcreateVarImpl(scip, &auxvar, name, minact, maxact, 0.0, SCIP_VARTYPE_CONTINUOUS, impltype,
    3942 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    3943 SCIP_CALL( SCIPaddVar(scip, auxvar) );
    3944
    3945#ifdef WITH_DEBUG_SOLUTION
    3946 if( SCIPdebugIsMainscip(scip) )
    3947 {
    3948 SCIP_Real debugsolval; /* value of auxvar in debug solution */
    3949 SCIP_Real val;
    3950
    3951 /* compute value of new variable in debug solution */
    3952 /* first \sum_j c_{ij} x_j (coefs[j] * vars[j]) */
    3953 debugsolval = 0.0;
    3954 for( i = 0; i < nvars; ++i )
    3955 {
    3956 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[i], &val) );
    3957 debugsolval += coefs[i] * val;
    3958 }
    3959
    3960 /* now multiply by x_i (facvar) */
    3961 SCIP_CALL( SCIPdebugGetSolVal(scip, facvar, &val) );
    3962 debugsolval *= val;
    3963
    3964 /* store debug solution value of auxiliary variable */
    3965 SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugsolval) );
    3966 }
    3967#endif
    3968
    3969 /* create and add z - maxact x <= 0 */
    3970 if( !SCIPisZero(scip, maxact) )
    3971 {
    3972 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    3973 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
    3974 SCIP_CALL( SCIPaddCons(scip, newcons) );
    3975 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    3976 if( naddconss != NULL )
    3977 ++(*naddconss);
    3978 }
    3979
    3980 /* create and add 0 <= z - minact x */
    3981 if( !SCIPisZero(scip, minact) )
    3982 {
    3983 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    3984 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
    3985 SCIP_CALL( SCIPaddCons(scip, newcons) );
    3986 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    3987 if( naddconss != NULL )
    3988 ++(*naddconss);
    3989 }
    3990
    3991 /* create and add minact <= sum_j c_j x_j - z + minact x_i */
    3992 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    3993 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
    3994 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
    3995 if( !SCIPisZero(scip, minact) )
    3996 {
    3997 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
    3998 }
    3999 SCIP_CALL( SCIPaddCons(scip, newcons) );
    4000 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    4001 if( naddconss != NULL )
    4002 ++(*naddconss);
    4003
    4004 /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
    4005 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
    4006 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
    4007 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
    4008 if( !SCIPisZero(scip, maxact) )
    4009 {
    4010 SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
    4011 }
    4012 SCIP_CALL( SCIPaddCons(scip, newcons) );
    4013 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    4014 if( naddconss != NULL )
    4015 ++(*naddconss);
    4016
    4017 /* create variable expression */
    4018 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
    4019
    4020 /* release auxvar */
    4021 SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
    4022
    4023 return SCIP_OKAY;
    4024}
    4025
    4026/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
    4027static
    4029 SCIP* scip, /**< SCIP data structure */
    4030 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4031 SCIP_CONS* cons, /**< constraint */
    4032 SCIP_EXPR* sumexpr, /**< expression */
    4033 int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
    4034 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
    4035 int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
    4036 )
    4037{
    4038 SCIP_EXPR** exprs = NULL;
    4039 SCIP_VAR** tmpvars = NULL;
    4040 SCIP_VAR** vars = NULL;
    4041 SCIP_VAR** xs = NULL;
    4042 SCIP_VAR** ys = NULL;
    4043 SCIP_Real* exprcoefs = NULL;
    4044 SCIP_Real* tmpcoefs = NULL;
    4045 SCIP_Real* sumcoefs;
    4046 SCIP_Bool* isused = NULL;
    4047 int* childidxs = NULL;
    4048 int* count = NULL;
    4049 int nchildren;
    4050 int nexprs = 0;
    4051 int nterms;
    4052 int nvars;
    4053 int ntotalvars;
    4054 int i;
    4055
    4056 assert(sumexpr != NULL);
    4057 assert(minterms > 1);
    4058 assert(newexpr != NULL);
    4059
    4060 *newexpr = NULL;
    4061
    4062 /* check whether sumexpr is indeed a sum */
    4063 if( !SCIPisExprSum(scip, sumexpr) )
    4064 return SCIP_OKAY;
    4065
    4066 nchildren = SCIPexprGetNChildren(sumexpr);
    4067 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
    4068 nvars = SCIPgetNVars(scip);
    4069 ntotalvars = SCIPgetNTotalVars(scip);
    4070
    4071 /* check whether there are enough terms available */
    4072 if( nchildren < minterms )
    4073 return SCIP_OKAY;
    4074
    4075 /* allocate memory */
    4076 SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
    4077 SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
    4078 SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
    4079
    4080 /* collect all bilinear binary product terms */
    4081 SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
    4082
    4083 /* check whether there are enough terms available */
    4084 if( nterms < minterms )
    4085 goto TERMINATE;
    4086
    4087 /* store how often each variable appears in a bilinear binary product */
    4089 SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
    4090 SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
    4091
    4092 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
    4093 SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
    4094 SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
    4095 SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
    4096
    4097 for( i = 0; i < nterms; ++i )
    4098 {
    4099 int xidx;
    4100 int yidx;
    4101
    4102 assert(xs[i] != NULL);
    4103 assert(ys[i] != NULL);
    4104
    4105 xidx = SCIPvarGetIndex(xs[i]);
    4106 assert(xidx < ntotalvars);
    4107 yidx = SCIPvarGetIndex(ys[i]);
    4108 assert(yidx < ntotalvars);
    4109
    4110 ++count[xidx];
    4111 ++count[yidx];
    4112
    4113 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
    4114 SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
    4115 }
    4116
    4117 /* sort variables; don't change order of count array because it depends on problem indices */
    4118 {
    4119 int* tmpcount;
    4120
    4121 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
    4122 SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
    4123 SCIPfreeBufferArray(scip, &tmpcount);
    4124 }
    4125
    4126 for( i = 0; i < nvars; ++i )
    4127 {
    4128 SCIP_VAR* facvar = vars[i];
    4129 int ntmpvars = 0;
    4130 int j;
    4131
    4132 /* skip candidate if there are not enough terms left */
    4133 if( count[SCIPvarGetIndex(vars[i])] < minterms )
    4134 continue;
    4135
    4136 SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
    4137
    4138 /* collect variables for x_i * sum_j c_ij x_j */
    4139 for( j = 0; j < nterms; ++j )
    4140 {
    4141 int childidx = childidxs[j];
    4142 assert(childidx >= 0 && childidx < nchildren);
    4143
    4144 if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
    4145 {
    4146 SCIP_Real coef;
    4147 int xidx;
    4148 int yidx;
    4149
    4150 coef = sumcoefs[childidx];
    4151 assert(coef != 0.0);
    4152
    4153 /* collect corresponding variable */
    4154 tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
    4155 tmpcoefs[ntmpvars] = coef;
    4156 ++ntmpvars;
    4157
    4158 /* update counters */
    4159 xidx = SCIPvarGetIndex(xs[j]);
    4160 assert(xidx < ntotalvars);
    4161 yidx = SCIPvarGetIndex(ys[j]);
    4162 assert(yidx < ntotalvars);
    4163 --count[xidx];
    4164 --count[yidx];
    4165 assert(count[xidx] >= 0);
    4166 assert(count[yidx] >= 0);
    4167
    4168 /* mark term to be used */
    4169 isused[childidx] = TRUE;
    4170 }
    4171 }
    4172 assert(ntmpvars >= minterms);
    4173 assert(SCIPvarGetIndex(facvar) < ntotalvars);
    4174 assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
    4175
    4176 /* create required constraints and store the generated expression */
    4177 SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
    4178 exprcoefs[nexprs] = 1.0;
    4179 ++nexprs;
    4180 }
    4181
    4182 /* factorization was only successful if at least one expression has been generated */
    4183 if( nexprs > 0 )
    4184 {
    4185 int nexprsold = nexprs;
    4186
    4187 /* add all children of the sum that have not been used */
    4188 for( i = 0; i < nchildren; ++i )
    4189 {
    4190 if( !isused[i] )
    4191 {
    4192 exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
    4193 exprcoefs[nexprs] = sumcoefs[i];
    4194 ++nexprs;
    4195 }
    4196 }
    4197
    4198 /* create a new sum expression */
    4199 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
    4200
    4201 /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
    4202 for( i = 0; i < nexprsold; ++i )
    4203 {
    4204 SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
    4205 }
    4206 }
    4207
    4208TERMINATE:
    4209 /* free memory */
    4210 SCIPfreeBufferArrayNull(scip, &tmpcoefs);
    4211 SCIPfreeBufferArrayNull(scip, &tmpvars);
    4212 SCIPfreeBufferArrayNull(scip, &exprcoefs);
    4215 SCIPfreeBufferArrayNull(scip, &isused);
    4217 SCIPfreeBufferArray(scip, &childidxs);
    4220
    4221 return SCIP_OKAY;
    4222}
    4223
    4224/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
    4225static
    4227 SCIP* scip, /**< SCIP data structure */
    4228 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4229 SCIP_EXPR* prodexpr, /**< product expression */
    4230 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
    4231 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
    4232 SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
    4233 )
    4234{
    4235 SCIP_VAR** vars;
    4236 SCIP_CONS* cons;
    4237 SCIP_Real* coefs;
    4238 SCIP_VAR* w;
    4239 char* name;
    4240 int nchildren;
    4241 int i;
    4242
    4243 assert(conshdlr != NULL);
    4244 assert(prodexpr != NULL);
    4245 assert(SCIPisExprProduct(scip, prodexpr));
    4246 assert(newexpr != NULL);
    4247
    4248 nchildren = SCIPexprGetNChildren(prodexpr);
    4249 assert(nchildren >= 2);
    4250
    4251 /* memory to store the variables of the variable expressions (+1 for w) and their name */
    4252 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
    4253 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
    4254 SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
    4255
    4256 /* prepare the names of the variable and the constraints */
    4257 /* coverity[secure_coding] */
    4258 strcpy(name, "binreform");
    4259 for( i = 0; i < nchildren; ++i )
    4260 {
    4261 vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
    4262 coefs[i] = 1.0;
    4263 assert(vars[i] != NULL);
    4264 (void) strcat(name, "_");
    4265 (void) strcat(name, SCIPvarGetName(vars[i]));
    4266
    4267 assert(SCIPvarIsBinary(vars[i]) && SCIPvarGetImplType(vars[i]) != SCIP_IMPLINTTYPE_WEAK);
    4268 }
    4269
    4270 /* create and add variable */
    4271 SCIP_CALL( SCIPcreateVarImpl(scip, &w, name, 0.0, 1.0, 0.0,
    4273 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    4275 SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
    4276
    4277#ifdef WITH_DEBUG_SOLUTION
    4278 if( SCIPdebugIsMainscip(scip) )
    4279 {
    4280 SCIP_Real debugsolval; /* value of auxvar in debug solution */
    4281 SCIP_Real val;
    4282
    4283 /* compute value of new variable in debug solution (\prod_i vars[i]) */
    4284 debugsolval = 1.0;
    4285 for( i = 0; i < nchildren; ++i )
    4286 {
    4287 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[i], &val) );
    4288 debugsolval *= val;
    4289 }
    4290
    4291 /* store debug solution value of auxiliary variable */
    4292 SCIP_CALL( SCIPdebugAddSolVal(scip, w, debugsolval) );
    4293 }
    4294#endif
    4295
    4296 /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
    4297 if( nchildren == 2 && !empathy4and )
    4298 {
    4299 SCIP_VAR* x = vars[0];
    4300 SCIP_VAR* y = vars[1];
    4301
    4302 assert(x != NULL);
    4303 assert(y != NULL);
    4304 assert(x != y);
    4305
    4306 /* create and add x - w >= 0 */
    4307 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
    4308 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
    4309 SCIP_CALL( SCIPaddCons(scip, cons) );
    4310 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    4311
    4312 /* create and add y - w >= 0 */
    4313 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
    4314 SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
    4315 SCIP_CALL( SCIPaddCons(scip, cons) );
    4316 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    4317
    4318 /* create and add x + y - w <= 1 */
    4319 vars[2] = w;
    4320 coefs[2] = -1.0;
    4321 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
    4322 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
    4323 SCIP_CALL( SCIPaddCons(scip, cons) );
    4324 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    4325
    4326 /* update number of added constraints */
    4327 if( naddconss != NULL )
    4328 *naddconss += 3;
    4329 }
    4330 else
    4331 {
    4332 /* create, add, and release AND constraint */
    4333 SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
    4334 SCIP_CALL( SCIPaddCons(scip, cons) );
    4335 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
    4336 SCIPdebugMsg(scip, " create AND constraint\n");
    4337
    4338 /* update number of added constraints */
    4339 if( naddconss != NULL )
    4340 *naddconss += 1;
    4341 }
    4342
    4343 /* create variable expression */
    4344 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
    4345
    4346 /* release created variable */
    4348
    4349 /* free memory */
    4350 SCIPfreeBufferArray(scip, &name);
    4351 SCIPfreeBufferArray(scip, &coefs);
    4352 SCIPfreeBufferArray(scip, &vars);
    4353
    4354 return SCIP_OKAY;
    4355}
    4356
    4357/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
    4358static
    4360 SCIP* scip, /**< SCIP data structure */
    4361 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4362 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
    4363 SCIP_EXPR* prodexpr, /**< product expression */
    4364 SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
    4365 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
    4366 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
    4367 )
    4368{
    4369 SCIP_CONSHDLRDATA* conshdlrdata;
    4370 int nchildren;
    4371
    4372 assert(prodexpr != NULL);
    4373 assert(newexpr != NULL);
    4374
    4375 *newexpr = NULL;
    4376
    4377 /* only consider products of binary variables */
    4378 if( !isBinaryProduct(scip, prodexpr) )
    4379 return SCIP_OKAY;
    4380
    4381 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4382 assert(conshdlrdata != NULL);
    4383 nchildren = SCIPexprGetNChildren(prodexpr);
    4384 assert(nchildren >= 2);
    4385
    4386 /* check whether there is already an expression that represents the product */
    4387 if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
    4388 {
    4389 *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
    4390 assert(*newexpr != NULL);
    4391
    4392 /* capture expression */
    4393 SCIPcaptureExpr(*newexpr);
    4394 }
    4395 else
    4396 {
    4397 SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
    4398
    4399 if( nchildren == 2 )
    4400 {
    4401 SCIP_CLIQUE** xcliques;
    4402 SCIP_VAR* x;
    4403 SCIP_VAR* y;
    4404 SCIP_Bool found_clique = FALSE;
    4405 int c;
    4406
    4407 /* get variables from the product expression */
    4408 x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
    4409 assert(x != NULL);
    4410 y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
    4411 assert(y != NULL);
    4412 assert(x != y);
    4413
    4414 /* first try to find a clique containing both variables */
    4415 xcliques = SCIPvarGetCliques(x, TRUE);
    4416
    4417 /* look in cliques containing x */
    4418 for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
    4419 {
    4420 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
    4421 {
    4422 /* create zero value expression */
    4423 SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
    4424
    4425 if( nchgcoefs != NULL )
    4426 *nchgcoefs += 1;
    4427
    4428 found_clique = TRUE;
    4429 break;
    4430 }
    4431
    4432 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
    4433 {
    4434 /* create variable expression for x */
    4435 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
    4436
    4437 if( nchgcoefs != NULL )
    4438 *nchgcoefs += 2;
    4439
    4440 found_clique = TRUE;
    4441 break;
    4442 }
    4443 }
    4444
    4445 if( !found_clique )
    4446 {
    4447 xcliques = SCIPvarGetCliques(x, FALSE);
    4448
    4449 /* look in cliques containing complement of x */
    4450 for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
    4451 {
    4452 if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
    4453 {
    4454 /* create variable expression for y */
    4455 SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
    4456
    4457 if( nchgcoefs != NULL )
    4458 *nchgcoefs += 1;
    4459
    4460 found_clique = TRUE;
    4461 break;
    4462 }
    4463
    4464 if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
    4465 {
    4466 /* create sum expression */
    4467 SCIP_EXPR* sum_children[2];
    4468 SCIP_Real sum_coefs[2];
    4469 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
    4470 SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
    4471 sum_coefs[0] = 1.0;
    4472 sum_coefs[1] = 1.0;
    4473 SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
    4474
    4475 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
    4476 SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
    4477
    4478 if( nchgcoefs != NULL )
    4479 *nchgcoefs += 3;
    4480
    4481 found_clique = TRUE;
    4482 break;
    4483 }
    4484 }
    4485 }
    4486
    4487 /* if the variables are not in a clique, do standard linearization */
    4488 if( !found_clique )
    4489 {
    4490 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
    4491 }
    4492 }
    4493 else
    4494 {
    4495 /* linearize binary product using an AND constraint because nchildren > 2 */
    4496 SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
    4497 }
    4498
    4499 /* hash variable expression */
    4500 SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
    4501 }
    4502
    4503 return SCIP_OKAY;
    4504}
    4505
    4506/** helper function to replace binary products in a given constraint */
    4507static
    4509 SCIP* scip, /**< SCIP data structure */
    4510 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4511 SCIP_CONS* cons, /**< constraint */
    4512 SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
    4513 SCIP_EXPRITER* it, /**< expression iterator */
    4514 int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
    4515 int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
    4516 )
    4517{
    4518 SCIP_CONSHDLRDATA* conshdlrdata;
    4519 SCIP_CONSDATA* consdata;
    4520 SCIP_EXPR* expr;
    4521
    4522 assert(conshdlr != NULL);
    4523 assert(cons != NULL);
    4524 assert(exprmap != NULL);
    4525 assert(it != NULL);
    4526
    4527 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4528 assert(conshdlrdata != NULL);
    4529
    4530 consdata = SCIPconsGetData(cons);
    4531 assert(consdata != NULL);
    4532 assert(consdata->expr != NULL);
    4533
    4534 SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
    4535
    4536 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    4537 {
    4538 SCIP_EXPR* newexpr = NULL;
    4539 SCIP_EXPR* childexpr;
    4540 int childexpridx;
    4541
    4542 childexpridx = SCIPexpriterGetChildIdxDFS(it);
    4543 assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
    4544 childexpr = SCIPexpriterGetChildExprDFS(it);
    4545 assert(childexpr != NULL);
    4546
    4547 /* try to factorize variables in a sum expression that contains several products of binary variables */
    4548 if( conshdlrdata->reformbinprodsfac > 1 )
    4549 {
    4550 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
    4551 }
    4552
    4553 /* try to create an expression that represents a product of binary variables */
    4554 if( newexpr == NULL )
    4555 {
    4556 SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
    4557 }
    4558
    4559 if( newexpr != NULL )
    4560 {
    4561 assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
    4562
    4563 /* replace product expression */
    4564 SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
    4565
    4566 /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
    4567 SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
    4568
    4569 /* mark the constraint to not be simplified anymore */
    4570 consdata->issimplified = FALSE;
    4571 }
    4572 }
    4573
    4574 return SCIP_OKAY;
    4575}
    4576
    4577/** reformulates products of binary variables during presolving in the following way:
    4578 *
    4579 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
    4580 * 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}:
    4581 * \f[
    4582 * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
    4583 * \f]
    4584 *
    4585 * 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 \f$x_j\f$.
    4586 * These cliques allow for a better reformulation. There are four cases:
    4587 *
    4588 * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
    4589 * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
    4590 * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
    4591 * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
    4592 *
    4593 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
    4594 *
    4595 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
    4596 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
    4597 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
    4598 * Such a lower sum is reformulated with only one extra variable w_i:
    4599 * \f{align}{
    4600 * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
    4601 * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
    4602 * \text{minact}\, x_i & \leq w_i, \\
    4603 * w_i &\leq \text{maxact}\, x_i, \\
    4604 * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
    4605 * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
    4606 * \f}
    4607 * 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
    4608 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
    4609 * of terms are prioritized.
    4610 */
    4611static
    4613 SCIP* scip, /**< SCIP data structure */
    4614 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4615 SCIP_CONS** conss, /**< constraints */
    4616 int nconss, /**< total number of constraints */
    4617 int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
    4618 int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
    4619 )
    4620{
    4621 SCIP_CONSHDLRDATA* conshdlrdata;
    4622 SCIP_HASHMAP* exprmap;
    4623 SCIP_EXPRITER* it;
    4624 int c;
    4625
    4626 assert(conshdlr != NULL);
    4627
    4628 /* no nonlinear constraints or binary variables -> skip */
    4629 if( nconss == 0 || SCIPgetNBinVars(scip) + SCIPgetNImplVars(scip) == 0 )
    4630 return SCIP_OKAY;
    4631 assert(conss != NULL);
    4632
    4633 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4634 assert(conshdlrdata != NULL);
    4635
    4636 /* create expression hash map */
    4638
    4639 /* create expression iterator */
    4643
    4644 SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
    4645
    4646 for( c = 0; c < nconss; ++c )
    4647 {
    4648 SCIP_CONSDATA* consdata;
    4649 SCIP_EXPR* newexpr = NULL;
    4650
    4651 assert(conss[c] != NULL);
    4652
    4653 consdata = SCIPconsGetData(conss[c]);
    4654 assert(consdata != NULL);
    4655
    4656 /* try to reformulate the root expression */
    4657 if( conshdlrdata->reformbinprodsfac > 1 )
    4658 {
    4659 SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
    4660 }
    4661
    4662 /* release the root node if another expression has been found */
    4663 if( newexpr != NULL )
    4664 {
    4665 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    4666 consdata->expr = newexpr;
    4667
    4668 /* mark constraint to be not simplified anymore */
    4669 consdata->issimplified = FALSE;
    4670 }
    4671
    4672 /* replace each product of binary variables separately */
    4673 SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
    4674 }
    4675
    4676 /* free memory */
    4677 SCIPhashmapFree(&exprmap);
    4678 SCIPfreeExpriter(&it);
    4679
    4680 return SCIP_OKAY;
    4681}
    4682
    4683/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
    4684 *
    4685 * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
    4686 * Then scale by -1 if
    4687 * - \f$n_+ < n_-\f$, or
    4688 * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
    4689 */
    4690static
    4692 SCIP* scip, /**< SCIP data structure */
    4693 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    4694 SCIP_CONS* cons, /**< nonlinear constraint */
    4695 SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
    4696 )
    4697{
    4698 SCIP_CONSDATA* consdata;
    4699 int i;
    4700
    4701 assert(cons != NULL);
    4702
    4703 consdata = SCIPconsGetData(cons);
    4704 assert(consdata != NULL);
    4705
    4706 if( SCIPisExprSum(scip, consdata->expr) )
    4707 {
    4708 SCIP_Real* coefs;
    4709 SCIP_Real constant;
    4710 int nchildren;
    4711 int counter = 0;
    4712
    4713 coefs = SCIPgetCoefsExprSum(consdata->expr);
    4714 constant = SCIPgetConstantExprSum(consdata->expr);
    4715 nchildren = SCIPexprGetNChildren(consdata->expr);
    4716
    4717 /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
    4718 if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
    4719 {
    4720 SCIP_EXPR* expr;
    4721 expr = consdata->expr;
    4722
    4723 consdata->expr = SCIPexprGetChildren(expr)[0];
    4724 assert(!SCIPisExprSum(scip, consdata->expr));
    4725
    4726 SCIPcaptureExpr(consdata->expr);
    4727
    4728 SCIPswapReals(&consdata->lhs, &consdata->rhs);
    4729 consdata->lhs = -consdata->lhs;
    4730 consdata->rhs = -consdata->rhs;
    4731
    4732 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
    4733 *changed = TRUE;
    4734 return SCIP_OKAY;
    4735 }
    4736
    4737 /* compute n_+ - n_i */
    4738 for( i = 0; i < nchildren; ++i )
    4739 counter += coefs[i] > 0 ? 1 : -1;
    4740
    4741 if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
    4742 {
    4743 SCIP_EXPR* expr;
    4744 SCIP_Real* newcoefs;
    4745
    4746 /* allocate memory */
    4747 SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
    4748
    4749 for( i = 0; i < nchildren; ++i )
    4750 newcoefs[i] = -coefs[i];
    4751
    4752 /* create a new sum expression */
    4753 SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
    4754
    4755 /* replace expression in constraint data and scale sides */
    4756 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    4757 consdata->expr = expr;
    4758 SCIPswapReals(&consdata->lhs, &consdata->rhs);
    4759 consdata->lhs = -consdata->lhs;
    4760 consdata->rhs = -consdata->rhs;
    4761
    4762 /* free memory */
    4763 SCIPfreeBufferArray(scip, &newcoefs);
    4764
    4765 *changed = TRUE;
    4766 }
    4767 }
    4768
    4769 return SCIP_OKAY;
    4770}
    4771
    4772/** forbid multiaggrations of variables that appear nonlinear in constraints */
    4773static
    4775 SCIP* scip, /**< SCIP data structure */
    4776 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4777 SCIP_CONS** conss, /**< constraints */
    4778 int nconss /**< number of constraints */
    4779 )
    4780{
    4781 SCIP_EXPRITER* it;
    4782 SCIP_CONSDATA* consdata;
    4783 SCIP_EXPR* expr;
    4784 int c;
    4785
    4786 assert(scip != NULL);
    4787 assert(conshdlr != NULL);
    4788
    4789 if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
    4790 return SCIP_OKAY;
    4791
    4794
    4795 for( c = 0; c < nconss; ++c )
    4796 {
    4797 consdata = SCIPconsGetData(conss[c]);
    4798 assert(consdata != NULL);
    4799
    4800 /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
    4801 * i.e., skip children of sum that are variables
    4802 */
    4803 if( SCIPisExprSum(scip, consdata->expr) )
    4804 {
    4805 int i;
    4806 SCIP_EXPR* child;
    4807 for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
    4808 {
    4809 child = SCIPexprGetChildren(consdata->expr)[i];
    4810
    4811 /* skip variable expression, as they correspond to a linear term */
    4812 if( SCIPisExprVar(scip, child) )
    4813 continue;
    4814
    4815 for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    4816 if( SCIPisExprVar(scip, expr) )
    4817 {
    4819 }
    4820 }
    4821 }
    4822 else
    4823 {
    4824 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    4825 if( SCIPisExprVar(scip, expr) )
    4826 {
    4828 }
    4829 }
    4830 }
    4831
    4832 SCIPfreeExpriter(&it);
    4833
    4834 return SCIP_OKAY;
    4835}
    4836
    4837/** simplifies expressions and replaces common subexpressions for a set of constraints
    4838 * @todo put the constant to the constraint sides
    4839 */
    4840static
    4842 SCIP* scip, /**< SCIP data structure */
    4843 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    4844 SCIP_CONS** conss, /**< constraints */
    4845 int nconss, /**< total number of constraints */
    4846 SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
    4847 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
    4848 int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
    4849 int* naddconss, /**< counter to add number of added constraints, or NULL */
    4850 int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
    4851 )
    4852{
    4853 SCIP_CONSHDLRDATA* conshdlrdata;
    4854 SCIP_CONSDATA* consdata;
    4855 int* nlockspos;
    4856 int* nlocksneg;
    4857 SCIP_Bool havechange;
    4858 int i;
    4859
    4860 assert(scip != NULL);
    4861 assert(conshdlr != NULL);
    4862 assert(conss != NULL);
    4863 assert(nconss > 0);
    4864 assert(infeasible != NULL);
    4865
    4866 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    4867 assert(conshdlrdata != NULL);
    4868
    4869 /* update number of canonicalize calls */
    4870 ++(conshdlrdata->ncanonicalizecalls);
    4871
    4872 SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
    4873
    4874 *infeasible = FALSE;
    4875
    4876 /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
    4877 havechange = conshdlrdata->ncanonicalizecalls == 1;
    4878
    4879 /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
    4880 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
    4881
    4882 /* allocate memory for storing locks of each constraint */
    4883 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
    4884 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
    4885
    4886 /* unlock all constraints */
    4887 for( i = 0; i < nconss; ++i )
    4888 {
    4889 assert(conss[i] != NULL);
    4890
    4891 consdata = SCIPconsGetData(conss[i]);
    4892 assert(consdata != NULL);
    4893
    4894 /* remember locks */
    4895 nlockspos[i] = consdata->nlockspos;
    4896 nlocksneg[i] = consdata->nlocksneg;
    4897
    4898 /* remove locks */
    4899 SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
    4900 assert(consdata->nlockspos == 0);
    4901 assert(consdata->nlocksneg == 0);
    4902 }
    4903
    4904#ifndef NDEBUG
    4905 /* check whether all locks of each expression have been removed */
    4906 for( i = 0; i < nconss; ++i )
    4907 {
    4908 SCIP_EXPR* expr;
    4909 SCIP_EXPRITER* it;
    4910
    4912
    4913 consdata = SCIPconsGetData(conss[i]);
    4914 assert(consdata != NULL);
    4915
    4917 for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    4918 {
    4919 assert(expr != NULL);
    4920 assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
    4921 assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
    4922 }
    4923 SCIPfreeExpriter(&it);
    4924 }
    4925#endif
    4926
    4927 /* reformulate products of binary variables */
    4928 if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
    4929 && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
    4930 {
    4931 int tmpnaddconss = 0;
    4932 int tmpnchgcoefs = 0;
    4933
    4934 /* call this function before simplification because expressions might not be simplified after reformulating
    4935 * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
    4936 */
    4937 SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
    4938
    4939 /* update counters */
    4940 if( naddconss != NULL )
    4941 *naddconss += tmpnaddconss;
    4942 if( nchgcoefs != NULL )
    4943 *nchgcoefs += tmpnchgcoefs;
    4944
    4945 /* check whether at least one expression has changed */
    4946 if( tmpnaddconss + tmpnchgcoefs > 0 )
    4947 havechange = TRUE;
    4948 }
    4949
    4950 for( i = 0; i < nconss; ++i )
    4951 {
    4952 consdata = SCIPconsGetData(conss[i]);
    4953 assert(consdata != NULL);
    4954
    4955 /* call simplify for each expression */
    4956 if( !consdata->issimplified && consdata->expr != NULL )
    4957 {
    4958 SCIP_EXPR* simplified;
    4959 SCIP_Bool changed;
    4960
    4961 changed = FALSE;
    4962 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
    4963 consdata->issimplified = TRUE;
    4964
    4965 if( changed )
    4966 havechange = TRUE;
    4967
    4968 /* 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").
    4969 * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
    4970 */
    4971 if( simplified != consdata->expr )
    4972 {
    4973 assert(changed);
    4974
    4975 /* release old expression */
    4976 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    4977
    4978 /* store simplified expression */
    4979 consdata->expr = simplified;
    4980 }
    4981 else
    4982 {
    4983 /* The simplify captures simplified in any case, also if nothing has changed.
    4984 * Therefore, we have to release it here.
    4985 */
    4986 SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
    4987 }
    4988
    4989 if( *infeasible )
    4990 break;
    4991
    4992 /* scale constraint sides */
    4993 SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
    4994
    4995 if( changed )
    4996 havechange = TRUE;
    4997
    4998 /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
    4999 if( SCIPisExprValue(scip, consdata->expr) )
    5000 {
    5001 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
    5002 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
    5003 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
    5004 {
    5005 SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
    5006 SCIPdebugPrintCons(scip, conss[i], NULL);
    5007 *infeasible = TRUE;
    5008 break;
    5009 }
    5010 else
    5011 {
    5012 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
    5013 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
    5014 if( ndelconss != NULL )
    5015 ++*ndelconss;
    5016 havechange = TRUE;
    5017 }
    5018 }
    5019 }
    5020 }
    5021
    5022 /* replace common subexpressions */
    5023 if( havechange && !*infeasible )
    5024 {
    5025 SCIP_CONS** consssorted;
    5026 SCIP_EXPR** rootexprs;
    5027 SCIP_Bool replacedroot;
    5028
    5029 SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
    5030 for( i = 0; i < nconss; ++i )
    5031 rootexprs[i] = SCIPconsGetData(conss[i])->expr;
    5032
    5033 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
    5034
    5035 /* update pointer to root expr in constraints, if any has changed
    5036 * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
    5037 */
    5038 if( replacedroot )
    5039 for( i = 0; i < nconss; ++i )
    5040 SCIPconsGetData(conss[i])->expr = rootexprs[i];
    5041
    5042 SCIPfreeBufferArray(scip, &rootexprs);
    5043
    5044 /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
    5045 * been changed after simplification; now we completely recollect all variable expression and variable events
    5046 */
    5047
    5048 /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
    5049 * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
    5050 */
    5051 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
    5052 SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
    5053
    5054 for( i = nconss-1; i >= 0; --i )
    5055 {
    5056 assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
    5057 if( SCIPconsIsDeleted(consssorted[i]) )
    5058 continue;
    5059
    5060 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
    5061 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
    5062 }
    5063 for( i = 0; i < nconss; ++i )
    5064 {
    5065 if( SCIPconsIsDeleted(consssorted[i]) )
    5066 continue;
    5067
    5068 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
    5069 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
    5070 }
    5071
    5072 SCIPfreeBufferArray(scip, &consssorted);
    5073
    5074 /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
    5075 * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
    5076 * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
    5077 */
    5078 SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
    5079 }
    5080
    5081 /* restore locks */
    5082 for( i = 0; i < nconss; ++i )
    5083 {
    5084 if( SCIPconsIsDeleted(conss[i]) )
    5085 continue;
    5086
    5087 SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
    5088 }
    5089
    5090 /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
    5091 * TODO can we skip this in presoltiming fast?
    5092 */
    5093 if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
    5094 {
    5095 /* reset one of the number of detections counter to count only current presolving round */
    5096 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    5097 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
    5098
    5099 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
    5100 }
    5101
    5102 /* free allocated memory */
    5103 SCIPfreeBufferArray(scip, &nlocksneg);
    5104 SCIPfreeBufferArray(scip, &nlockspos);
    5105
    5106 SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
    5107
    5108 return SCIP_OKAY;
    5109}
    5110
    5111/** merges constraints that have the same root expression */
    5112static
    5114 SCIP* scip, /**< SCIP data structure */
    5115 SCIP_CONS** conss, /**< constraints to process */
    5116 int nconss, /**< number of constraints */
    5117 SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
    5118 )
    5119{
    5120 SCIP_HASHMAP* expr2cons;
    5121 SCIP_Bool* updatelocks;
    5122 int* nlockspos;
    5123 int* nlocksneg;
    5124 int c;
    5125
    5126 assert(success != NULL);
    5127
    5128 *success = FALSE;
    5129
    5130 /* not enough constraints available */
    5131 if( nconss <= 1 )
    5132 return SCIP_OKAY;
    5133
    5134 SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
    5135 SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
    5136 SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
    5137 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
    5138
    5139 for( c = 0; c < nconss; ++c )
    5140 {
    5141 SCIP_CONSDATA* consdata;
    5142
    5143 /* ignore deleted constraints */
    5144 if( SCIPconsIsDeleted(conss[c]) )
    5145 continue;
    5146
    5147 consdata = SCIPconsGetData(conss[c]);
    5148 assert(consdata != NULL);
    5149
    5150 /* add expression to the hash map if not seen so far */
    5151 if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
    5152 {
    5153 SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
    5154 }
    5155 else
    5156 {
    5157 SCIP_CONSDATA* imgconsdata;
    5158 int idx;
    5159
    5160 idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
    5161 assert(idx >= 0 && idx < nconss);
    5162
    5163 imgconsdata = SCIPconsGetData(conss[idx]);
    5164 assert(imgconsdata != NULL);
    5165 assert(imgconsdata->expr == consdata->expr);
    5166
    5167 SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
    5168 SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
    5169
    5170 /* check whether locks need to be updated */
    5171 if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
    5172 || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
    5173 {
    5174 nlockspos[idx] = imgconsdata->nlockspos;
    5175 nlocksneg[idx] = imgconsdata->nlocksneg;
    5176 SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
    5177 updatelocks[idx] = TRUE;
    5178 }
    5179
    5180 /* update constraint sides */
    5181 imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
    5182 imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
    5183
    5184 /* delete constraint */
    5185 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
    5186 *success = TRUE;
    5187 }
    5188 }
    5189
    5190 /* restore locks of updated constraints */
    5191 if( *success )
    5192 {
    5193 for( c = 0; c < nconss; ++c )
    5194 {
    5195 if( updatelocks[c] )
    5196 {
    5197 SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
    5198 }
    5199 }
    5200 }
    5201
    5202 /* free memory */
    5203 SCIPfreeBufferArray(scip, &nlocksneg);
    5204 SCIPfreeBufferArray(scip, &nlockspos);
    5205 SCIPfreeBufferArray(scip, &updatelocks);
    5206 SCIPhashmapFree(&expr2cons);
    5207
    5208 return SCIP_OKAY;
    5209}
    5210
    5211/** interval evaluation of variables as used in redundancy check
    5212 *
    5213 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
    5214 */
    5215static
    5216SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
    5217{ /*lint --e{715}*/
    5218 SCIP_CONSHDLRDATA* conshdlrdata;
    5219 SCIP_INTERVAL interval;
    5220 SCIP_Real lb;
    5221 SCIP_Real ub;
    5222
    5223 assert(scip != NULL);
    5224 assert(var != NULL);
    5225
    5226 conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
    5227 assert(conshdlrdata != NULL);
    5228
    5229 if( conshdlrdata->globalbounds )
    5230 {
    5231 lb = SCIPvarGetLbGlobal(var);
    5232 ub = SCIPvarGetUbGlobal(var);
    5233 }
    5234 else
    5235 {
    5236 lb = SCIPvarGetLbLocal(var);
    5237 ub = SCIPvarGetUbLocal(var);
    5238 }
    5239 assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
    5240
    5241 /* relax variable bounds, if there are bounds and variable is not fixed
    5242 * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
    5243 */
    5244 if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
    5245 {
    5246 if( !SCIPisInfinity(scip, -lb) )
    5247 lb -= SCIPfeastol(scip);
    5248
    5249 if( !SCIPisInfinity(scip, ub) )
    5250 ub += SCIPfeastol(scip);
    5251 }
    5252
    5253 /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
    5256 assert(lb <= ub);
    5257
    5258 SCIPintervalSetBounds(&interval, lb, ub);
    5259
    5260 return interval;
    5261}
    5262
    5263/** removes constraints that are always feasible or very simple
    5264 *
    5265 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
    5266 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
    5267 * might violate variable bounds by up to feastol, too.
    5268 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
    5269 *
    5270 * Also removes constraints of the form lhs &le; variable &le; rhs.
    5271 *
    5272 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
    5273 *
    5274 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
    5275 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
    5276 * would appear as if the constraint is redundant.
    5277 */
    5278static
    5280 SCIP* scip, /**< SCIP data structure */
    5281 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    5282 SCIP_CONS** conss, /**< constraints to propagate */
    5283 int nconss, /**< total number of constraints */
    5284 SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
    5285 int* ndelconss, /**< buffer to add the number of deleted constraints */
    5286 int* nchgbds /**< buffer to add the number of variable bound tightenings */
    5287 )
    5288{
    5289 SCIP_CONSHDLRDATA* conshdlrdata;
    5290 SCIP_CONSDATA* consdata;
    5291 SCIP_INTERVAL activity;
    5292 SCIP_INTERVAL sides;
    5293 int i;
    5294
    5295 assert(scip != NULL);
    5296 assert(conshdlr != NULL);
    5297 assert(conss != NULL);
    5298 assert(nconss >= 0);
    5299 assert(cutoff != NULL);
    5300 assert(ndelconss != NULL);
    5301 assert(nchgbds != NULL);
    5302
    5303 /* no constraints to check */
    5304 if( nconss == 0 )
    5305 return SCIP_OKAY;
    5306
    5307 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5308 assert(conshdlrdata != NULL);
    5309
    5310 /* increase curboundstag and set lastvaractivitymethodchange
    5311 * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
    5312 * for the redundancy check differently than for domain propagation
    5313 * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
    5314 */
    5315 ++conshdlrdata->curboundstag;
    5316 assert(conshdlrdata->curboundstag > 0);
    5317 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
    5318 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
    5319 conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
    5320
    5321 SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
    5322
    5323 *cutoff = FALSE;
    5324 for( i = 0; i < nconss; ++i )
    5325 {
    5326 if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
    5327 continue;
    5328
    5329 consdata = SCIPconsGetData(conss[i]);
    5330 assert(consdata != NULL);
    5331
    5332 /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
    5333 if( SCIPisExprValue(scip, consdata->expr) )
    5334 {
    5335 SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
    5336
    5337 if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
    5338 (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
    5339 {
    5340 SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
    5341 *cutoff = TRUE;
    5342
    5343 goto TERMINATE;
    5344 }
    5345
    5346 SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
    5347
    5348 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
    5349 ++*ndelconss;
    5350
    5351 continue;
    5352 }
    5353
    5354 /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
    5355 if( SCIPisExprVar(scip, consdata->expr) )
    5356 {
    5357 SCIP_VAR* var;
    5358 SCIP_Bool tightened;
    5359
    5360 var = SCIPgetVarExprVar(consdata->expr);
    5361 assert(var != NULL);
    5362
    5363 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);
    5364
    5365 /* ensure that variable bounds are within constraint sides */
    5366 if( !SCIPisInfinity(scip, -consdata->lhs) )
    5367 {
    5368 SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
    5369
    5370 if( tightened )
    5371 ++*nchgbds;
    5372
    5373 if( *cutoff )
    5374 goto TERMINATE;
    5375 }
    5376
    5377 if( !SCIPisInfinity(scip, consdata->rhs) )
    5378 {
    5379 SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
    5380
    5381 if( tightened )
    5382 ++*nchgbds;
    5383
    5384 if( *cutoff )
    5385 goto TERMINATE;
    5386 }
    5387
    5388 /* delete the (now) redundant constraint locally */
    5389 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
    5390 ++*ndelconss;
    5391
    5392 continue;
    5393 }
    5394
    5395 /* reevaluate expression activity, now using intEvalVarRedundancyCheck
    5396 * we relax variable bounds by feastol here, as solutions that are checked later can also violate
    5397 * variable bounds by up to feastol
    5398 * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
    5399 */
    5400 SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
    5401 SCIPdebugPrintCons(scip, conss[i], NULL);
    5402
    5403 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
    5404 assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
    5405
    5406 /* it is unlikely that we detect infeasibility by doing forward propagation */
    5407 if( *cutoff )
    5408 {
    5409 SCIPdebugMsg(scip, " -> cutoff\n");
    5410 goto TERMINATE;
    5411 }
    5412
    5413 assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
    5414 activity = SCIPexprGetActivity(consdata->expr);
    5415
    5416 /* relax sides by feastol
    5417 * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
    5418 */
    5419 SCIPintervalSetBounds(&sides,
    5420 SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
    5421 SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
    5422
    5423 if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
    5424 {
    5425 SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
    5426
    5427 SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
    5428 ++*ndelconss;
    5429
    5430 continue;
    5431 }
    5432
    5433 SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
    5434 }
    5435
    5436TERMINATE:
    5437 /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
    5438 ++conshdlrdata->curboundstag;
    5439 conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
    5440 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
    5441 conshdlrdata->intevalvar = intEvalVarBoundTightening;
    5442
    5443 return SCIP_OKAY;
    5444}
    5445
    5446/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
    5447static
    5449 SCIP* scip, /**< SCIP data structure */
    5450 SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
    5451 SCIP_CONS* cons, /**< source constraint to try to convert */
    5452 SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
    5453 int* nupgdconss, /**< buffer to increase if constraint was upgraded */
    5454 int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
    5455 )
    5456{
    5457 SCIP_CONSHDLRDATA* conshdlrdata;
    5458 SCIP_CONSDATA* consdata;
    5459 SCIP_CONS** upgdconss;
    5460 int upgdconsssize;
    5461 int nupgdconss_;
    5462 int i;
    5463
    5464 assert(scip != NULL);
    5465 assert(conshdlr != NULL);
    5466 assert(cons != NULL);
    5467 assert(!SCIPconsIsModifiable(cons));
    5468 assert(upgraded != NULL);
    5469 assert(nupgdconss != NULL);
    5470 assert(naddconss != NULL);
    5471
    5472 *upgraded = FALSE;
    5473
    5474 nupgdconss_ = 0;
    5475
    5476 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5477 assert(conshdlrdata != NULL);
    5478
    5479 /* if there are no upgrade methods, we can stop */
    5480 if( conshdlrdata->nconsupgrades == 0 )
    5481 return SCIP_OKAY;
    5482
    5483 upgdconsssize = 2;
    5484 SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
    5485
    5486 /* call the upgrading methods */
    5487 SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
    5489
    5490 consdata = SCIPconsGetData(cons);
    5491 assert(consdata != NULL);
    5492
    5493 /* try all upgrading methods in priority order in case the upgrading step is enable */
    5494 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
    5495 {
    5496 if( !conshdlrdata->consupgrades[i]->active )
    5497 continue;
    5498
    5499 assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
    5500
    5501 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
    5502
    5503 while( nupgdconss_ < 0 )
    5504 {
    5505 /* upgrade function requires more memory: resize upgdconss and call again */
    5506 assert(-nupgdconss_ > upgdconsssize);
    5507 upgdconsssize = -nupgdconss_;
    5508 SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
    5509
    5510 SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
    5511
    5512 assert(nupgdconss_ != 0);
    5513 }
    5514
    5515 if( nupgdconss_ > 0 )
    5516 {
    5517 /* got upgrade */
    5518 int j;
    5519
    5520 SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
    5521
    5522 /* add the upgraded constraints to the problem and forget them */
    5523 for( j = 0; j < nupgdconss_; ++j )
    5524 {
    5525 SCIPdebugMsgPrint(scip, "\t");
    5526 SCIPdebugPrintCons(scip, upgdconss[j], NULL);
    5527
    5528 SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
    5529 SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
    5530 }
    5531
    5532 /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
    5533 *nupgdconss += 1;
    5534 *naddconss += nupgdconss_ - 1;
    5535 *upgraded = TRUE;
    5536
    5537 /* delete upgraded constraint */
    5538 SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
    5539 SCIP_CALL( SCIPdelCons(scip, cons) );
    5540
    5541 break;
    5542 }
    5543 }
    5544
    5545 SCIPfreeBufferArray(scip, &upgdconss);
    5546
    5547 return SCIP_OKAY;
    5548}
    5549
    5550/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
    5551 * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
    5552 * variable bounds, and is not binary
    5553 */
    5554static
    5556 SCIP* scip, /**< SCIP data structure */
    5557 SCIP_EXPR* expr /**< variable expression */
    5558 )
    5559{
    5560 SCIP_VAR* var;
    5561 SCIP_EXPR_OWNERDATA* ownerdata;
    5562
    5563 assert(SCIPisExprVar(scip, expr));
    5564
    5565 var = SCIPgetVarExprVar(expr);
    5566 assert(var != NULL);
    5567
    5568 ownerdata = SCIPexprGetOwnerData(expr);
    5569 assert(ownerdata != NULL);
    5570
    5571 return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
    5572 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
    5573 && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
    5577}
    5578
    5579/** removes all variable expressions that are contained in a given expression from a hash map */
    5580static
    5582 SCIP* scip, /**< SCIP data structure */
    5583 SCIP_EXPR* expr, /**< expression */
    5584 SCIP_EXPRITER* it, /**< expression iterator */
    5585 SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
    5586 )
    5587{
    5588 SCIP_EXPR* e;
    5589
    5590 for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
    5591 {
    5592 if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
    5593 {
    5594 SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
    5595 }
    5596 }
    5597
    5598 return SCIP_OKAY;
    5599}
    5600
    5601/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
    5602 * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
    5603 *
    5604 * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
    5605 * Otherwise, a bound disjunction constraint is added.
    5606 *
    5607 * @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?)
    5608 */
    5609static
    5611 SCIP* scip, /**< SCIP data structure */
    5612 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    5613 SCIP_CONS* cons, /**< nonlinear constraint */
    5614 int* nchgvartypes, /**< pointer to store the total number of changed variable types */
    5615 int* naddconss, /**< pointer to store the total number of added constraints */
    5616 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
    5617 )
    5618{
    5619 SCIP_CONSHDLRDATA* conshdlrdata;
    5620 SCIP_CONSDATA* consdata;
    5621 SCIP_EXPR** singlelocked;
    5622 SCIP_HASHMAP* exprcands;
    5623 SCIP_Bool hasbounddisj;
    5624 SCIP_Bool haslhs;
    5625 SCIP_Bool hasrhs;
    5626 int nsinglelocked = 0;
    5627 int i;
    5628
    5629 assert(conshdlr != NULL);
    5630 assert(cons != NULL);
    5631 assert(nchgvartypes != NULL);
    5632 assert(naddconss != NULL);
    5633 assert(infeasible != NULL);
    5634
    5635 *nchgvartypes = 0;
    5636 *naddconss = 0;
    5637 *infeasible = FALSE;
    5638
    5639 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    5640 assert(conshdlrdata != NULL);
    5641 consdata = SCIPconsGetData(cons);
    5642 assert(consdata != NULL);
    5643
    5644 /* only consider constraints with one finite side */
    5645 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
    5646 return SCIP_OKAY;
    5647
    5648 /* only consider sum expressions */
    5649 if( !SCIPisExprSum(scip, consdata->expr) )
    5650 return SCIP_OKAY;
    5651
    5652 /* remember which side is finite */
    5653 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
    5654 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
    5655
    5656 /* allocate memory */
    5657 SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
    5658 SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
    5659
    5660 /* check all variable expressions for single locked variables */
    5661 for( i = 0; i < consdata->nvarexprs; ++i )
    5662 {
    5663 assert(consdata->varexprs[i] != NULL);
    5664
    5665 if( isSingleLockedCand(scip, consdata->varexprs[i]) )
    5666 {
    5667 SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
    5668 singlelocked[nsinglelocked++] = consdata->varexprs[i];
    5669 }
    5670 }
    5671 SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
    5672
    5673 if( nsinglelocked > 0 )
    5674 {
    5675 SCIP_EXPR** children;
    5676 SCIP_EXPRITER* it;
    5677 int nchildren;
    5678
    5679 children = SCIPexprGetChildren(consdata->expr);
    5680 nchildren = SCIPexprGetNChildren(consdata->expr);
    5681
    5682 /* create iterator */
    5686
    5687 for( i = 0; i < nchildren; ++i )
    5688 {
    5689 SCIP_EXPR* child;
    5690 SCIP_Real coef;
    5691
    5692 child = children[i];
    5693 assert(child != NULL);
    5694 coef = SCIPgetCoefsExprSum(consdata->expr)[i];
    5695
    5696 /* ignore linear terms */
    5697 if( SCIPisExprVar(scip, child) )
    5698 continue;
    5699
    5700 /* consider products coef * prod_j f_j(x)
    5701 * - if f_j(x) is a single variable, ignore it
    5702 * - if f_j(x) = x^(2k), then keep it if product is concave when fixing all other factor;
    5703 * 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
    5704 * - remove all other variable expressions from exprcand
    5705 */
    5706 if( SCIPisExprProduct(scip, child) )
    5707 {
    5708 int j;
    5709 SCIP_INTERVAL productactivity;
    5710 SCIP_Bool keepevenpower;
    5711
    5712 /* activity has been ensured to be uptodate (or at least still valid) by
    5713 * call to SCIPregisterExprUsageNonlinear() in detectNlhdlrs() in canonicalize
    5714 */
    5715 productactivity = SCIPexprGetActivity(child);
    5716
    5717 /* check whether variables in even-powered factor terms can be restricted to bounds (as in SCIPisExprPower() below) */
    5718 keepevenpower = (haslhs && productactivity.inf >= 0.0) || (hasrhs && productactivity.sup <= 0.0);
    5719
    5720 for( j = 0; j < SCIPexprGetNChildren(child); ++j )
    5721 {
    5722 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
    5723 assert(grandchild != NULL);
    5724
    5725 /* if grandchild is x^(2k), then do not remove x from exprcands */
    5726 if( keepevenpower && SCIPisExprPower(scip, grandchild) && SCIPisExprVar(scip, SCIPexprGetChildren(grandchild)[0]) )
    5727 {
    5728 SCIP_Real exponent = SCIPgetExponentExprPow(grandchild);
    5729
    5730 if( exponent > 1.0 && fmod(exponent, 2.0) == 0.0 )
    5731 continue;
    5732 }
    5733
    5734 if( !SCIPisExprVar(scip, grandchild) )
    5735 {
    5736 /* mark all variable expressions that are contained in the expression */
    5737 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
    5738 }
    5739 }
    5740 }
    5741 /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
    5742 * for an integer k >= 1
    5743 */
    5744 else if( SCIPisExprPower(scip, child) )
    5745 {
    5746 SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
    5747 SCIP_Real exponent = SCIPgetExponentExprPow(child);
    5748 SCIP_Bool valid;
    5749
    5750 /* check for even integral exponent */
    5751 valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
    5752
    5753 if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
    5754 {
    5755 /* mark all variable expressions that are contained in the expression */
    5756 SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
    5757 }
    5758 }
    5759 /* all other cases cannot be handled */
    5760 else
    5761 {
    5762 /* mark all variable expressions that are contained in the expression */
    5763 SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
    5764 }
    5765 }
    5766
    5767 /* free expression iterator */
    5768 SCIPfreeExpriter(&it);
    5769 }
    5770
    5771 /* check whether the bound disjunction constraint handler is available */
    5772 hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
    5773
    5774 /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
    5775 for( i = 0; i < nsinglelocked; ++i )
    5776 {
    5777 /* only consider expressions that are still contained in the exprcands map */
    5778 if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
    5779 {
    5780 SCIP_CONS* newcons;
    5781 SCIP_VAR* vars[2];
    5782 SCIP_BOUNDTYPE boundtypes[2];
    5783 SCIP_Real bounds[2];
    5784 char name[SCIP_MAXSTRLEN];
    5785 SCIP_VAR* var;
    5786
    5787 var = SCIPgetVarExprVar(singlelocked[i]);
    5788 assert(var != NULL);
    5789 SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
    5791
    5792 /* try to change the variable type to binary */
    5793 if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
    5794 {
    5796 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
    5797 ++(*nchgvartypes);
    5798
    5799 if( *infeasible )
    5800 {
    5801 SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
    5802 break;
    5803 }
    5804 }
    5805 /* add bound disjunction constraint if bounds of the variable are finite */
    5806 else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
    5807 {
    5808 vars[0] = var;
    5809 vars[1] = var;
    5810 boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
    5811 boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
    5812 bounds[0] = SCIPvarGetUbGlobal(var);
    5813 bounds[1] = SCIPvarGetLbGlobal(var);
    5814
    5815 SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
    5816
    5817 /* create, add, and release bound disjunction constraint */
    5818 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
    5819 SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
    5821 SCIP_CALL( SCIPaddCons(scip, newcons) );
    5822 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
    5823 ++(*naddconss);
    5824 }
    5825 }
    5826 }
    5827
    5828 /* free memory */
    5829 SCIPfreeBufferArray(scip, &singlelocked);
    5830 SCIPhashmapFree(&exprcands);
    5831
    5832 return SCIP_OKAY;
    5833}
    5834
    5835/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
    5836static
    5838 SCIP* scip, /**< SCIP data structure */
    5839 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    5840 SCIP_CONS** conss, /**< nonlinear constraints */
    5841 int nconss, /**< total number of nonlinear constraints */
    5842 int* nchgvartypes, /**< pointer to update the total number of changed variable types */
    5843 SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
    5844 )
    5845{
    5846 int c;
    5847
    5848 assert(scip != NULL);
    5849 assert(conshdlr != NULL);
    5850 assert(conss != NULL || nconss == 0);
    5851 assert(nchgvartypes != NULL);
    5852 assert(infeasible != NULL);
    5853
    5854 *infeasible = FALSE;
    5855
    5856 /* nothing can be done on purley continuous problem */
    5858 return SCIP_OKAY;
    5859
    5860 /* no continuous var can be made implicit-integer if there are no continuous variables */
    5861 if( SCIPgetNContVars(scip) == 0 )
    5862 return SCIP_OKAY;
    5863
    5864 for( c = 0; c < nconss; ++c )
    5865 {
    5866 SCIP_CONSDATA* consdata;
    5867 SCIP_EXPR** children;
    5868 int nchildren;
    5869 SCIP_Real* coefs;
    5870 SCIP_EXPR* cand = NULL;
    5871 SCIP_Real candcoef = 0.0;
    5872 int i;
    5873 SCIP_IMPLINTTYPE impltype;
    5874
    5875 assert(conss != NULL && conss[c] != NULL);
    5876
    5877 consdata = SCIPconsGetData(conss[c]);
    5878 assert(consdata != NULL);
    5879
    5880 /* the constraint must be an equality constraint */
    5881 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
    5882 continue;
    5883
    5884 /* the root expression needs to be a sum expression */
    5885 if( !SCIPisExprSum(scip, consdata->expr) )
    5886 continue;
    5887
    5888 children = SCIPexprGetChildren(consdata->expr);
    5889 nchildren = SCIPexprGetNChildren(consdata->expr);
    5890
    5891 /* the sum expression must have at least two children
    5892 * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
    5893 */
    5894 if( nchildren <= 1 )
    5895 continue;
    5896
    5897 coefs = SCIPgetCoefsExprSum(consdata->expr);
    5898
    5899 /* find first continuous variable and get value of its coefficient */
    5900 for( i = 0; i < nchildren; ++i )
    5901 {
    5902 if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
    5903 continue;
    5904
    5905 candcoef = coefs[i];
    5906 assert(candcoef != 0.0);
    5907
    5908 /* lhs/rhs - constant divided by candcoef must be integral
    5909 * if not, break with cand == NULL, so give up
    5910 */
    5911 if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
    5912 cand = children[i];
    5913
    5914 break;
    5915 }
    5916
    5917 /* no suitable continuous variable found */
    5918 if( cand == NULL )
    5919 continue;
    5920
    5921 impltype = SCIP_IMPLINTTYPE_STRONG;
    5922
    5923 /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
    5924 for( i = 0; i < nchildren; ++i )
    5925 {
    5926 if( children[i] == cand )
    5927 continue;
    5928
    5929 impltype = MIN(impltype, SCIPexprGetIntegrality(children[i]));
    5930 /* child i must be integral */
    5931 if( impltype == SCIP_IMPLINTTYPE_NONE )
    5932 {
    5933 cand = NULL;
    5934 break;
    5935 }
    5936
    5937 /* coefficient of child i must be integral if diving by candcoef */
    5938 if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
    5939 {
    5940 cand = NULL;
    5941 break;
    5942 }
    5943 }
    5944
    5945 if( cand == NULL )
    5946 continue;
    5947
    5948 SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
    5950
    5951 /* change variable type */
    5952 assert(impltype != SCIP_IMPLINTTYPE_NONE);
    5953
    5954 SCIP_CALL( SCIPchgVarImplType(scip, SCIPgetVarExprVar(cand), impltype, infeasible) );
    5955 ++(*nchgvartypes);
    5956
    5957 if( *infeasible )
    5958 return SCIP_OKAY;
    5959
    5960 /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
    5961 SCIPexprSetIntegrality(cand, impltype);
    5962 }
    5963
    5964 return SCIP_OKAY;
    5965}
    5966
    5967/** creates auxiliary variable for a given expression
    5968 *
    5969 * @note for a variable expression it does nothing
    5970 * @note this function can only be called in stage SCIP_STAGE_SOLVING
    5971 */
    5972static
    5974 SCIP* scip, /**< SCIP data structure */
    5975 SCIP_EXPR* expr /**< expression */
    5976 )
    5977{
    5978 SCIP_EXPR_OWNERDATA* ownerdata;
    5979 SCIP_CONSHDLRDATA* conshdlrdata;
    5980 SCIP_IMPLINTTYPE impltype;
    5981 SCIP_INTERVAL activity;
    5982 char name[SCIP_MAXSTRLEN];
    5983
    5984 assert(scip != NULL);
    5985 assert(expr != NULL);
    5986
    5987 ownerdata = SCIPexprGetOwnerData(expr);
    5988 assert(ownerdata != NULL);
    5989 assert(ownerdata->nauxvaruses > 0);
    5990
    5991 /* if we already have auxvar, then do nothing */
    5992 if( ownerdata->auxvar != NULL )
    5993 return SCIP_OKAY;
    5994
    5995 /* if expression is a variable-expression, then do nothing */
    5996 if( SCIPisExprVar(scip, expr) )
    5997 return SCIP_OKAY;
    5998
    6000 {
    6001 SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
    6002 return SCIP_INVALIDCALL;
    6003 }
    6004
    6005 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    6006 assert(conshdlrdata != NULL);
    6007 assert(conshdlrdata->auxvarid >= 0);
    6008
    6009 /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
    6010 * but it usually indicates a missing simplify
    6011 * if we find situations where we need to have an auxvar for a constant, then remove this assert
    6012 */
    6013 assert(!SCIPisExprValue(scip, expr));
    6014
    6015 /* create and capture auxiliary variable */
    6016 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
    6017 ++conshdlrdata->auxvarid;
    6018
    6019 /* type of auxiliary variable depends on integrality information of the expression */
    6020 impltype = SCIPexprGetIntegrality(expr);
    6021
    6022 /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
    6023 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
    6024 {
    6025 activity = SCIPexprGetActivity(expr);
    6026 /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
    6027 * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
    6028 * and abort in debug mode only
    6029 */
    6031 {
    6032 SCIPABORT();
    6034 }
    6035 }
    6036 else
    6038
    6039 /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
    6040 * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
    6041 */
    6042 if( SCIPgetDepth(scip) == 0 )
    6043 {
    6044 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name,
    6045 MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0,
    6046 SCIP_VARTYPE_CONTINUOUS, impltype,
    6047 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    6048 }
    6049 else
    6050 {
    6051 SCIP_CALL( SCIPcreateVarImpl(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
    6052 SCIP_VARTYPE_CONTINUOUS, impltype,
    6053 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
    6054 }
    6055
    6056 /* mark the auxiliary variable to be added for the relaxation only
    6057 * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
    6058 * or to copy the variable to a subscip
    6059 */
    6060 SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
    6061
    6062 SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
    6063
    6064 SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
    6065
    6066 /* add variable locks in both directions
    6067 * TODO should be sufficient to lock only according to expr->nlockspos/neg,
    6068 * but then we need to also update the auxvars locks when the expr locks change
    6069 */
    6070 SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
    6071
    6072#ifdef WITH_DEBUG_SOLUTION
    6073 if( SCIPdebugIsMainscip(scip) )
    6074 {
    6075 /* store debug solution value of auxiliary variable
    6076 * assumes that expression has been evaluated in debug solution before
    6077 */
    6078 SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
    6079 }
    6080#endif
    6081
    6082 if( SCIPgetDepth(scip) > 0 )
    6083 {
    6084 /* initialize local bounds to (locally valid) activity */
    6085 SCIP_Bool cutoff;
    6086 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
    6087 assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
    6088 }
    6089
    6090 return SCIP_OKAY;
    6091}
    6092
    6093/** initializes separation for constraint
    6094 *
    6095 * - ensures that activities are up to date in all expressions
    6096 * - creates auxiliary variables where required
    6097 * - calls propExprDomains() to possibly tighten auxvar bounds
    6098 * - calls separation initialization callback of nlhdlrs
    6099 */
    6100static
    6102 SCIP* scip, /**< SCIP data structure */
    6103 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    6104 SCIP_CONS** conss, /**< constraints */
    6105 int nconss, /**< number of constraints */
    6106 SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
    6107 )
    6108{
    6109 SCIP_CONSDATA* consdata;
    6110 SCIP_CONSHDLRDATA* conshdlrdata;
    6111 SCIP_EXPRITER* it;
    6112 SCIP_EXPR* expr;
    6113 SCIP_RESULT result;
    6114 SCIP_VAR* auxvar;
    6115 int nreductions = 0;
    6116 int c, e;
    6117
    6118 assert(scip != NULL);
    6119 assert(conshdlr != NULL);
    6120 assert(conss != NULL || nconss == 0);
    6121 assert(nconss >= 0);
    6122 assert(infeasible != NULL);
    6123
    6124 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6125 assert(conshdlrdata != NULL);
    6126
    6127 /* start with new propbounds (just to be sure, should not be needed) */
    6128 ++conshdlrdata->curpropboundstag;
    6129
    6132
    6133 /* first ensure activities are up to date and create auxvars */
    6134 *infeasible = FALSE;
    6135 for( c = 0; c < nconss; ++c )
    6136 {
    6137 assert(conss != NULL);
    6138 assert(conss[c] != NULL);
    6139
    6140 consdata = SCIPconsGetData(conss[c]);
    6141 assert(consdata != NULL);
    6142 assert(consdata->expr != NULL);
    6143
    6144#ifdef WITH_DEBUG_SOLUTION
    6145 if( SCIPdebugIsMainscip(scip) )
    6146 {
    6147 SCIP_SOL* debugsol;
    6148
    6149 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
    6150
    6151 if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
    6152 {
    6153 /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
    6154 * in createAuxVar()
    6155 */
    6156 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
    6157 }
    6158 }
    6159#endif
    6160
    6161 /* ensure we have a valid activity for auxvars and propExprDomains() call below */
    6162 SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
    6163
    6164 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    6165 {
    6166 if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
    6167 {
    6168 SCIP_CALL( createAuxVar(scip, expr) );
    6169 }
    6170 }
    6171
    6172 auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
    6173 if( auxvar != NULL )
    6174 {
    6175 SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
    6176 SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
    6177 /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
    6178 SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
    6179 if( *infeasible )
    6180 {
    6181 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
    6182 break;
    6183 }
    6184
    6185 SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
    6186 if( *infeasible )
    6187 {
    6188 SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
    6189 break;
    6190 }
    6191 }
    6192 }
    6193
    6194 /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
    6195 * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
    6196 * (e.g., log(x*y), which becomes log(w), w=x*y
    6197 * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
    6198 */
    6199 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
    6200 if( result == SCIP_CUTOFF )
    6201 *infeasible = TRUE;
    6202
    6203 /* now call initsepa of nlhdlrs
    6204 * TODO skip if !SCIPconsIsInitial(conss[c]) ?
    6205 * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
    6206 */
    6208 for( c = 0; c < nconss && !*infeasible; ++c )
    6209 {
    6210 assert(conss != NULL);
    6211 assert(conss[c] != NULL);
    6212
    6213 consdata = SCIPconsGetData(conss[c]);
    6214 assert(consdata != NULL);
    6215 assert(consdata->expr != NULL);
    6216
    6217 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
    6218 {
    6219 SCIP_EXPR_OWNERDATA* ownerdata;
    6220
    6221 ownerdata = SCIPexprGetOwnerData(expr);
    6222 assert(ownerdata != NULL);
    6223
    6224 if( ownerdata->nauxvaruses == 0 )
    6225 continue;
    6226
    6227 for( e = 0; e < ownerdata->nenfos; ++e )
    6228 {
    6229 SCIP_NLHDLR* nlhdlr;
    6230 SCIP_Bool underestimate;
    6231 SCIP_Bool overestimate;
    6232 assert(ownerdata->enfos[e] != NULL);
    6233
    6234 /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
    6235 * which participated in a previous initSepa() call
    6236 */
    6237 if( ownerdata->enfos[e]->issepainit )
    6238 continue;
    6239
    6240 /* only call initsepa if it will actually separate */
    6241 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
    6242 continue;
    6243
    6244 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    6245 assert(nlhdlr != NULL);
    6246
    6247 /* only init sepa if there is an initsepa callback */
    6248 if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
    6249 continue;
    6250
    6251 /* check whether expression needs to be under- or overestimated */
    6252 overestimate = ownerdata->nlocksneg > 0;
    6253 underestimate = ownerdata->nlockspos > 0;
    6254 assert(underestimate || overestimate);
    6255
    6256 SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
    6257
    6258 /* call the separation initialization callback of the nonlinear handler */
    6259 SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
    6260 ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
    6261 ownerdata->enfos[e]->issepainit = TRUE;
    6262
    6263 if( *infeasible )
    6264 {
    6265 /* stop everything if we detected infeasibility */
    6266 SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
    6267 break;
    6268 }
    6269 }
    6270 }
    6271 }
    6272
    6273 SCIPfreeExpriter(&it);
    6274
    6275 return SCIP_OKAY;
    6276}
    6277
    6278/** returns whether we are ok to branch on auxiliary variables
    6279 *
    6280 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
    6281 */
    6282static
    6284 SCIP* scip, /**< SCIP data structure */
    6285 SCIP_CONSHDLR* conshdlr /**< constraint handler */
    6286 )
    6287{
    6288 SCIP_CONSHDLRDATA* conshdlrdata;
    6289
    6290 assert(conshdlr != NULL);
    6291
    6292 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6293 assert(conshdlrdata != NULL);
    6294
    6295 return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
    6296}
    6297
    6298/** gets weight of variable when splitting violation score onto several variables in an expression */
    6299static
    6301 SCIP* scip, /**< SCIP data structure */
    6302 SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
    6303 SCIP_VAR* var, /**< variable */
    6304 SCIP_SOL* sol /**< current solution */
    6305 )
    6306{
    6307 SCIP_CONSHDLRDATA* conshdlrdata;
    6308
    6309 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6310 assert(conshdlrdata != NULL);
    6311
    6312 switch( conshdlrdata->branchviolsplit )
    6313 {
    6314 case 'u' : /* uniform: everyone gets the same score */
    6315 return 1.0;
    6316
    6317 case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
    6318 {
    6319 SCIP_Real weight;
    6320 weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
    6321 return MAX(0.05, weight);
    6322 }
    6323
    6324 case 'd' : /* domain width */
    6325 return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
    6326
    6327 case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
    6328 {
    6329 SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
    6330 assert(width > 0.0);
    6331 if( width > 10.0 )
    6332 return 10.0*log10(width);
    6333 if( width < 0.1 )
    6334 return 0.1/(-log10(width));
    6335 return width;
    6336 }
    6337
    6338 default :
    6339 SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
    6340 SCIPABORT();
    6341 return SCIP_INVALID;
    6342 }
    6343}
    6344
    6345/** adds violation-branching score to a set of expressions, thereby distributing the score
    6346 *
    6347 * Each expression must either be a variable expression or have an aux-variable.
    6348 *
    6349 * If unbounded variables are present, each unbounded var gets an even score.
    6350 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
    6351 */
    6352static
    6354 SCIP* scip, /**< SCIP data structure */
    6355 SCIP_EXPR** exprs, /**< expressions where to add branching score */
    6356 int nexprs, /**< number of expressions */
    6357 SCIP_Real violscore, /**< violation-branching score to add to expression */
    6358 SCIP_SOL* sol, /**< current solution */
    6359 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
    6360 )
    6361{
    6362 SCIP_CONSHDLR* conshdlr;
    6363 SCIP_VAR* var;
    6364 SCIP_Real weight;
    6365 SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
    6366 int nunbounded = 0; /* number of candidates with unbounded domain */
    6367 int i;
    6368
    6369 assert(exprs != NULL);
    6370 assert(nexprs >= 0);
    6371 assert(success != NULL);
    6372
    6373 if( nexprs == 1 )
    6374 {
    6375 SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
    6376 SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
    6378 *success = TRUE;
    6379 return;
    6380 }
    6381
    6382 if( nexprs == 0 )
    6383 {
    6384 *success = FALSE;
    6385 return;
    6386 }
    6387
    6388 conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
    6389
    6390 for( i = 0; i < nexprs; ++i )
    6391 {
    6392 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
    6393 assert(var != NULL);
    6394
    6396 ++nunbounded;
    6397 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
    6398 weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
    6399 }
    6400
    6401 *success = FALSE;
    6402 for( i = 0; i < nexprs; ++i )
    6403 {
    6404 var = SCIPgetExprAuxVarNonlinear(exprs[i]);
    6405 assert(var != NULL);
    6406
    6407 if( nunbounded > 0 )
    6408 {
    6410 {
    6411 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
    6412 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
    6413 100.0/nunbounded, violscore,
    6415 *success = TRUE;
    6416 }
    6417 }
    6418 else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
    6419 {
    6420 assert(weightsum > 0.0);
    6421
    6422 weight = getViolSplitWeight(scip, conshdlr, var, sol);
    6423 SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
    6424 SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
    6425 100*weight / weightsum, violscore,
    6427 *success = TRUE;
    6428 }
    6429 else
    6430 {
    6431 SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
    6433 }
    6434 }
    6435}
    6436
    6437/** adds violation-branching score to children of expression for given auxiliary variables
    6438 *
    6439 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
    6440 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
    6441 *
    6442 * @note This method may modify the given auxvars array by means of sorting.
    6443 */
    6444static
    6446 SCIP* scip, /**< SCIP data structure */
    6447 SCIP_EXPR* expr, /**< expression where to start searching */
    6448 SCIP_Real violscore, /**< violation score to add to expression */
    6449 SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
    6450 int nauxvars, /**< number of auxiliary variables */
    6451 SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
    6452 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
    6453 )
    6454{
    6455 SCIP_EXPRITER* it;
    6456 SCIP_VAR* auxvar;
    6457 SCIP_EXPR** exprs;
    6458 int nexprs;
    6459 int pos;
    6460
    6461 assert(scip != NULL);
    6462 assert(expr != NULL);
    6463 assert(auxvars != NULL);
    6464 assert(success != NULL);
    6465
    6466 /* sort variables to make lookup below faster */
    6467 SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
    6468
    6471
    6472 SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
    6473 nexprs = 0;
    6474
    6475 for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    6476 {
    6477 auxvar = SCIPgetExprAuxVarNonlinear(expr);
    6478 if( auxvar == NULL )
    6479 continue;
    6480
    6481 /* if auxvar of expr is contained in auxvars array, add branching score to expr */
    6482 if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
    6483 {
    6484 assert(auxvars[pos] == auxvar);
    6485
    6486 SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
    6487 exprs[nexprs++] = expr;
    6488
    6489 if( nexprs == nauxvars )
    6490 break;
    6491 }
    6492 }
    6493
    6494 SCIPfreeExpriter(&it);
    6495
    6496 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
    6497
    6498 SCIPfreeBufferArray(scip, &exprs);
    6499
    6500 return SCIP_OKAY;
    6501}
    6502
    6503/** registers all unfixed variables in violated constraints as branching candidates */
    6504static
    6506 SCIP* scip, /**< SCIP data structure */
    6507 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    6508 SCIP_CONS** conss, /**< constraints */
    6509 int nconss, /**< number of constraints */
    6510 int* nnotify /**< counter for number of notifications performed */
    6511 )
    6512{
    6513 SCIP_CONSDATA* consdata;
    6514 SCIP_VAR* var;
    6515 int c;
    6516 int i;
    6517
    6518 assert(conshdlr != NULL);
    6519 assert(conss != NULL || nconss == 0);
    6520 assert(nnotify != NULL);
    6521
    6522 *nnotify = 0;
    6523
    6524 for( c = 0; c < nconss; ++c )
    6525 {
    6526 assert(conss != NULL && conss[c] != NULL);
    6527
    6528 consdata = SCIPconsGetData(conss[c]);
    6529 assert(consdata != NULL);
    6530
    6531 /* consider only violated constraints */
    6532 if( !isConsViolated(scip, conss[c]) )
    6533 continue;
    6534
    6535 /* register all variables that have not been fixed yet */
    6536 assert(consdata->varexprs != NULL);
    6537 for( i = 0; i < consdata->nvarexprs; ++i )
    6538 {
    6539 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    6540 assert(var != NULL);
    6541
    6543 {
    6545 ++(*nnotify);
    6546 }
    6547 }
    6548 }
    6549
    6550 return SCIP_OKAY;
    6551}
    6552
    6553/** registers all variables in violated constraints with branching scores as external branching candidates */
    6554static
    6556 SCIP* scip, /**< SCIP data structure */
    6557 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    6558 SCIP_CONS** conss, /**< constraints */
    6559 int nconss, /**< number of constraints */
    6560 SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
    6561 )
    6562{
    6563 SCIP_CONSDATA* consdata;
    6564 SCIP_EXPRITER* it = NULL;
    6565 int c;
    6566
    6567 assert(conshdlr != NULL);
    6568 assert(success != NULL);
    6569
    6570 *success = FALSE;
    6571
    6572 if( branchAuxNonlinear(scip, conshdlr) )
    6573 {
    6576 }
    6577
    6578 /* register external branching candidates */
    6579 for( c = 0; c < nconss; ++c )
    6580 {
    6581 assert(conss != NULL && conss[c] != NULL);
    6582
    6583 consdata = SCIPconsGetData(conss[c]);
    6584 assert(consdata != NULL);
    6585 assert(consdata->varexprs != NULL);
    6586
    6587 /* consider only violated constraints */
    6588 if( !isConsViolated(scip, conss[c]) )
    6589 continue;
    6590
    6591 if( !branchAuxNonlinear(scip, conshdlr) )
    6592 {
    6593 int i;
    6594
    6595 /* if not branching on auxvars, then violation-branching scores will have been added to original variables
    6596 * only, so we can loop over variable expressions
    6597 */
    6598 for( i = 0; i < consdata->nvarexprs; ++i )
    6599 {
    6600 SCIP_Real violscore;
    6601 SCIP_Real lb;
    6602 SCIP_Real ub;
    6603 SCIP_VAR* var;
    6604
    6605 violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
    6606
    6607 /* skip variable expressions that do not have a violation score */
    6608 if( violscore == 0.0 )
    6609 continue;
    6610
    6611 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    6612 assert(var != NULL);
    6613
    6614 lb = SCIPvarGetLbLocal(var);
    6615 ub = SCIPvarGetUbLocal(var);
    6616
    6617 /* consider variable for branching if it has not been fixed yet */
    6618 if( !SCIPisEQ(scip, lb, ub) )
    6619 {
    6620 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
    6622 *success = TRUE;
    6623 }
    6624 else
    6625 {
    6626 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
    6627 }
    6628
    6629 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
    6630 * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
    6631 */
    6632 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
    6633 }
    6634 }
    6635 else
    6636 {
    6637 SCIP_EXPR* expr;
    6638 SCIP_VAR* var;
    6639 SCIP_Real lb;
    6640 SCIP_Real ub;
    6641 SCIP_Real violscore;
    6642
    6643 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    6644 {
    6645 violscore = SCIPgetExprViolScoreNonlinear(expr);
    6646 if( violscore == 0.0 )
    6647 continue;
    6648
    6649 /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
    6650 * variable, so this expression should either be an original variable or have an auxiliary variable
    6651 */
    6652 var = SCIPgetExprAuxVarNonlinear(expr);
    6653 assert(var != NULL);
    6654
    6655 lb = SCIPvarGetLbLocal(var);
    6656 ub = SCIPvarGetUbLocal(var);
    6657
    6658 /* consider variable for branching if it has not been fixed yet */
    6659 if( !SCIPisEQ(scip, lb, ub) )
    6660 {
    6661 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
    6662
    6664 *success = TRUE;
    6665 }
    6666 else
    6667 {
    6668 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
    6669 }
    6670 }
    6671 }
    6672 }
    6673
    6674 if( it != NULL )
    6675 SCIPfreeExpriter(&it);
    6676
    6677 return SCIP_OKAY;
    6678}
    6679
    6680/** collect branching candidates from violated constraints
    6681 *
    6682 * Fills array with expressions that serve as branching candidates.
    6683 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
    6684 * branching candidate.
    6685 *
    6686 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
    6687 * through variable-expressions only.
    6688 */
    6689static
    6691 SCIP* scip, /**< SCIP data structure */
    6692 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6693 SCIP_CONS** conss, /**< constraints to process */
    6694 int nconss, /**< number of constraints */
    6695 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
    6696 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    6697 SCIP_Longint soltag, /**< tag of solution */
    6698 BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
    6699 int* ncands /**< number of candidates found */
    6700 )
    6701{
    6702 SCIP_CONSHDLRDATA* conshdlrdata;
    6703 SCIP_CONSDATA* consdata;
    6704 SCIP_EXPRITER* it = NULL;
    6705 int c;
    6706 int attempt;
    6707 SCIP_VAR* var;
    6708
    6709 assert(scip != NULL);
    6710 assert(conshdlr != NULL);
    6711 assert(cands != NULL);
    6712 assert(ncands != NULL);
    6713
    6714 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6715 assert(conshdlrdata != NULL);
    6716
    6717 if( branchAuxNonlinear(scip, conshdlr) )
    6718 {
    6721 }
    6722
    6723 *ncands = 0;
    6724 for( attempt = 0; attempt < 2; ++attempt )
    6725 {
    6726 /* collect branching candidates from violated constraints
    6727 * in the first attempt, consider only constraints with large violation
    6728 * in the second attempt, consider all remaining violated constraints
    6729 */
    6730 for( c = 0; c < nconss; ++c )
    6731 {
    6732 SCIP_Real consviol;
    6733
    6734 assert(conss != NULL && conss[c] != NULL);
    6735
    6736 /* consider only violated constraints */
    6737 if( !isConsViolated(scip, conss[c]) )
    6738 continue;
    6739
    6740 consdata = SCIPconsGetData(conss[c]);
    6741 assert(consdata != NULL);
    6742 assert(consdata->varexprs != NULL);
    6743
    6744 SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
    6745
    6746 if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
    6747 continue;
    6748 else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
    6749 continue;
    6750
    6751 if( !branchAuxNonlinear(scip, conshdlr) )
    6752 {
    6753 int i;
    6754
    6755 /* if not branching on auxvars, then violation-branching scores will be available for original variables
    6756 * only, so we can loop over variable expressions
    6757 * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
    6758 * variable, therefore we invalidate the score of a variable after processing it.
    6759 */
    6760 for( i = 0; i < consdata->nvarexprs; ++i )
    6761 {
    6762 SCIP_Real lb;
    6763 SCIP_Real ub;
    6764
    6765 /* skip variable expressions that do not have a valid violation score */
    6766 if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
    6767 continue;
    6768
    6769 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    6770 assert(var != NULL);
    6771
    6772 lb = SCIPvarGetLbLocal(var);
    6773 ub = SCIPvarGetUbLocal(var);
    6774
    6775 /* skip already fixed variable */
    6776 if( SCIPisEQ(scip, lb, ub) )
    6777 {
    6778 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
    6779 continue;
    6780 }
    6781
    6782 assert(*ncands + 1 < SCIPgetNVars(scip));
    6783 cands[*ncands].expr = consdata->varexprs[i];
    6784 cands[*ncands].var = var;
    6785 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
    6786 cands[*ncands].fractionality = 0.0;
    6787 ++(*ncands);
    6788
    6789 /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
    6790 * several times as external branching candidate */
    6791 SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
    6792 }
    6793 }
    6794 else
    6795 {
    6796 SCIP_EXPR* expr;
    6797 SCIP_Real lb;
    6798 SCIP_Real ub;
    6799
    6800 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    6801 {
    6802 if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
    6803 continue;
    6804
    6805 /* if some nlhdlr added a branching score for this expression, then it considered this expression as
    6806 * variables, so this expression should either be an original variable or have an auxiliary variable
    6807 */
    6808 var = SCIPgetExprAuxVarNonlinear(expr);
    6809 assert(var != NULL);
    6810
    6811 lb = SCIPvarGetLbLocal(var);
    6812 ub = SCIPvarGetUbLocal(var);
    6813
    6814 /* skip already fixed variable */
    6815 if( SCIPisEQ(scip, lb, ub) )
    6816 {
    6817 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
    6818 continue;
    6819 }
    6820
    6821 assert(*ncands + 1 < SCIPgetNVars(scip));
    6822 cands[*ncands].expr = expr;
    6823 cands[*ncands].var = var;
    6824 cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
    6825 cands[*ncands].fractionality = 0.0;
    6826 ++(*ncands);
    6827 }
    6828 }
    6829 }
    6830
    6831 /* if we have branching candidates, then we don't need another attempt */
    6832 if( *ncands > 0 )
    6833 break;
    6834 }
    6835
    6836 if( it != NULL )
    6837 SCIPfreeExpriter(&it);
    6838
    6839 return SCIP_OKAY;
    6840}
    6841
    6842/** computes a branching score for a variable that reflects how important branching on this variable would be for
    6843 * improving the dual bound from the LP relaxation
    6844 *
    6845 * Assume the Lagrangian for the current LP is something of the form
    6846 * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
    6847 * where x are the original variables, z the auxiliary variables,
    6848 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
    6849 *
    6850 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
    6851 * If we could have used not only an estimator, but the actual function f(x), then this would
    6852 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
    6853 * Using a lot of handwaving, we claim that
    6854 * lambda_i * (f(x) - a_i'x + b_i)
    6855 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
    6856 * If an estimator depended on local bounds, then it could be improved by branching.
    6857 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
    6858 *
    6859 * 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.
    6860 * To scale, we divide by the LP objective value (if >1).
    6861 *
    6862 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
    6863 * these are affected by the bounds on original variables indirectly (through forward-propagation)
    6864 *
    6865 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
    6866 * in effect, we should go from the row to the expression for which it was generated and consider only variables that
    6867 * would also be branching candidates
    6868 */
    6869static
    6871 SCIP* scip, /**< SCIP data structure */
    6872 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    6873 SCIP_VAR* var /**< variable */
    6874 )
    6875{
    6876 SCIP_COL* col;
    6877 SCIP_ROW** rows;
    6878 int nrows;
    6879 int r;
    6880 SCIP_Real dualscore;
    6881
    6882 assert(scip != NULL);
    6883 assert(conshdlr != NULL);
    6884 assert(var != NULL);
    6885
    6886 /* if LP not solved, then the dual branching score is not available */
    6888 return 0.0;
    6889
    6890 /* if var is not in the LP, then the dual branching score is not available */
    6892 return 0.0;
    6893
    6894 col = SCIPvarGetCol(var);
    6895 assert(col != NULL);
    6896
    6897 if( !SCIPcolIsInLP(col) )
    6898 return 0.0;
    6899
    6900 nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
    6901 rows = SCIPcolGetRows(col);
    6902
    6903 /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
    6904
    6905 /* aggregate duals from all rows from consexpr with non-zero dual
    6906 * TODO: this is a quick-and-dirty implementation, and not used by default
    6907 * in the long run, this should be either removed or replaced by a proper implementation
    6908 */
    6909 dualscore = 0.0;
    6910 for( r = 0; r < nrows; ++r )
    6911 {
    6912 SCIP_Real estimategap;
    6913 const char* estimategapstr;
    6914
    6915 /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
    6916 * these would typically be local, unless they are created at the root node
    6917 * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
    6918 if( !SCIProwIsLocal(rows[r]) )
    6919 continue;
    6920 */
    6921 if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
    6922 continue;
    6923 if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
    6924 continue;
    6925
    6926 estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
    6927 if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
    6928 continue;
    6929 estimategap = atof(estimategapstr + 13);
    6930 assert(estimategap >= 0.0);
    6931 if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
    6932 estimategap = SCIPgetHugeValue(scip);
    6933
    6934 /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
    6935 SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
    6936
    6937 dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
    6938 }
    6939
    6940 /* divide by optimal value of LP for scaling */
    6941 dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
    6942
    6943 return dualscore;
    6944}
    6945
    6946/** computes branching scores (including weighted score) for a set of candidates
    6947 *
    6948 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
    6949 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
    6950 *
    6951 * For each score, compute the maximum over all candidates.
    6952 *
    6953 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
    6954 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
    6955 * score of all candidates.
    6956 * Further divide by the sum of all weights where a score was available (even if the score was 0).
    6957 *
    6958 * For example:
    6959 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
    6960 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
    6961 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
    6962 * - 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.
    6963 * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
    6964 */
    6965static
    6967 SCIP* scip, /**< SCIP data structure */
    6968 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    6969 BRANCHCAND* cands, /**< branching candidates */
    6970 int ncands, /**< number of candidates */
    6971 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
    6972 SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
    6973 )
    6974{
    6975 SCIP_CONSHDLRDATA* conshdlrdata;
    6976 BRANCHCAND maxscore;
    6977 int c;
    6978
    6979 assert(scip != NULL);
    6980 assert(conshdlr != NULL);
    6981 assert(cands != NULL);
    6982 assert(ncands > 0);
    6983
    6984 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    6985 assert(conshdlrdata != NULL);
    6986
    6987 /* initialize counts to 0 */
    6988 memset(&maxscore, 0, sizeof(BRANCHCAND));
    6989
    6990 for( c = 0; c < ncands; ++c )
    6991 {
    6992 if( conshdlrdata->branchviolweight > 0.0 )
    6993 {
    6994 /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
    6995 maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
    6996 }
    6997
    6998 if( conshdlrdata->branchfracweight > 0.0 && SCIPvarIsNonimpliedIntegral(cands[c].var) )
    6999 {
    7000 /* when collecting for branching on fractionality (cands[c].expr == NULL), only fractional integer variables
    7001 * should appear as candidates here and their fractionality should have been recorded in branchingIntegralOrNonlinear
    7002 */
    7003 assert(cands[c].expr != NULL || cands[c].fractionality > 0.0);
    7004
    7005 if( considerfracnl && cands[c].fractionality == 0.0 )
    7006 {
    7007 /* for an integer variable that is subject to spatial branching, we also record the fractionality (but separately from auxviol)
    7008 * if considerfracnl is TRUE; this way, we can give preference to fractional integer nonlinear variables
    7009 */
    7010 SCIP_Real solval;
    7011 SCIP_Real rounded;
    7012
    7013 solval = SCIPgetSolVal(scip, sol, cands[c].var);
    7014 rounded = SCIPround(scip, solval);
    7015
    7016 cands[c].fractionality = REALABS(solval - rounded);
    7017 }
    7018
    7019 maxscore.fractionality = MAX(cands[c].fractionality, maxscore.fractionality);
    7020 }
    7021 else
    7022 cands[c].fractionality = 0.0;
    7023
    7024 if( conshdlrdata->branchdomainweight > 0.0 && cands[c].expr != NULL )
    7025 {
    7026 SCIP_Real domainwidth;
    7027 SCIP_VAR* var;
    7028
    7029 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
    7030 assert(var != NULL);
    7031
    7032 /* get domain width, taking infinity at 1e20 on purpose */
    7033 domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
    7034
    7035 /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
    7036 * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
    7037 * the idea is to penalize very large and very small domains
    7038 */
    7039 if( domainwidth >= 1.0 )
    7040 cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
    7041 else
    7042 cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
    7043
    7044 maxscore.domain = MAX(cands[c].domain, maxscore.domain);
    7045 }
    7046 else
    7047 cands[c].domain = 0.0;
    7048
    7049 if( conshdlrdata->branchdualweight > 0.0 && cands[c].expr != NULL )
    7050 {
    7051 SCIP_VAR* var;
    7052
    7053 var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
    7054 assert(var != NULL);
    7055
    7056 cands[c].dual = getDualBranchscore(scip, conshdlr, var);
    7057 maxscore.dual = MAX(cands[c].dual, maxscore.dual);
    7058 }
    7059 else
    7060 cands[c].dual = 0.0;
    7061
    7062 if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
    7063 {
    7064 SCIP_VAR* var;
    7065
    7066 var = cands[c].var;
    7067 assert(var != NULL);
    7068
    7069 if( cands[c].expr != NULL )
    7070 {
    7072 cands[c].pscost = SCIP_INVALID;
    7073 else
    7074 {
    7075 SCIP_Real brpoint;
    7076 SCIP_Real pscostdown;
    7077 SCIP_Real pscostup;
    7078 char strategy;
    7079
    7080 /* decide how to compute pseudo-cost scores
    7081 * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
    7082 * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
    7083 */
    7084 if( !SCIPvarIsIntegral(var) )
    7085 strategy = conshdlrdata->branchpscostupdatestrategy;
    7086 else
    7087 strategy = 'l';
    7088
    7089 brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
    7090
    7091 /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
    7092 * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
    7093 * For here, I use a simple #counts >= branchpscostreliable.
    7094 * TODO use SCIPgetVarPseudocostCount() instead?
    7095 */
    7096 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
    7097 {
    7098 switch( strategy )
    7099 {
    7100 case 's' :
    7101 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
    7102 break;
    7103 case 'd' :
    7104 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
    7105 break;
    7106 case 'l' :
    7107 if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
    7108 pscostdown = SCIP_INVALID;
    7109 else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
    7110 pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
    7111 else
    7112 pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, sol, var) - SCIPadjustedVarUb(scip, var, brpoint)));
    7113 break;
    7114 default :
    7115 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
    7116 pscostdown = SCIP_INVALID;
    7117 }
    7118 }
    7119 else
    7120 pscostdown = SCIP_INVALID;
    7121
    7122 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
    7123 {
    7124 switch( strategy )
    7125 {
    7126 case 's' :
    7127 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
    7128 break;
    7129 case 'd' :
    7130 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
    7131 break;
    7132 case 'l' :
    7133 if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
    7134 pscostup = SCIP_INVALID;
    7135 else if( SCIPgetSolVal(scip, sol, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
    7136 pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
    7137 else
    7138 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, sol, var) );
    7139 break;
    7140 default :
    7141 SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
    7142 pscostup = SCIP_INVALID;
    7143 }
    7144 }
    7145 else
    7146 pscostup = SCIP_INVALID;
    7147
    7148 /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
    7149 * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
    7150 */
    7151 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
    7152 cands[c].pscost = SCIP_INVALID;
    7153 else if( pscostdown == SCIP_INVALID )
    7154 cands[c].pscost = pscostup;
    7155 else if( pscostup == SCIP_INVALID )
    7156 cands[c].pscost = pscostdown;
    7157 else
    7158 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
    7159 }
    7160 }
    7161 else
    7162 {
    7163 SCIP_Real pscostdown;
    7164 SCIP_Real pscostup;
    7165 SCIP_Real solval;
    7166
    7167 solval = SCIPgetSolVal(scip, sol, cands[c].var);
    7168
    7169 /* the calculation for pscostdown/up follows SCIPgetVarPseudocostScore(),
    7170 * i.e., set solvaldelta to the (negated) difference between variable value and rounded down value for pscostdown
    7171 * and different between variable value and rounded up value for pscostup
    7172 */
    7173 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
    7174 pscostdown = SCIPgetVarPseudocostVal(scip, var, SCIPfeasCeil(scip, solval - 1.0) - solval);
    7175 else
    7176 pscostdown = SCIP_INVALID;
    7177
    7178 if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
    7179 pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPfeasFloor(scip, solval + 1.0) - solval);
    7180 else
    7181 pscostup = SCIP_INVALID;
    7182
    7183 /* TODO see above for nonlinear variable case */
    7184 if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
    7185 cands[c].pscost = SCIP_INVALID;
    7186 else if( pscostdown == SCIP_INVALID )
    7187 cands[c].pscost = pscostup;
    7188 else if( pscostup == SCIP_INVALID )
    7189 cands[c].pscost = pscostdown;
    7190 else
    7191 cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
    7192 }
    7193
    7194 if( cands[c].pscost != SCIP_INVALID )
    7195 maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
    7196 }
    7197 else
    7198 cands[c].pscost = SCIP_INVALID;
    7199
    7200 if( conshdlrdata->branchvartypeweight > 0.0 )
    7201 {
    7202 switch( SCIPvarGetType(cands[c].var) )
    7203 {
    7205 cands[c].vartype = 1.0;
    7206 break;
    7208 cands[c].vartype = 0.1;
    7209 break;
    7211 if( SCIPvarIsImpliedIntegral(cands[c].var) )
    7212 cands[c].vartype = 0.01;
    7213 else
    7214 cands[c].vartype = 0.0;
    7215 break;
    7216 default:
    7217 SCIPerrorMessage("invalid variable type\n");
    7218 SCIPABORT();
    7219 return; /*lint !e527*/
    7220 } /*lint !e788*/
    7221
    7222 maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
    7223 }
    7224 }
    7225
    7226 /* now compute a weighted score for each candidate from the single scores
    7227 * the single scores are scaled to be in [0,1] for this
    7228 */
    7229 for( c = 0; c < ncands; ++c )
    7230 {
    7231 SCIP_Real weightsum;
    7232
    7233 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(cands[c].var), SCIPvarGetLbLocal(cands[c].var), SCIPvarGetUbLocal(cands[c].var)); )
    7234
    7235 cands[c].weighted = 0.0;
    7236 weightsum = 0.0;
    7237
    7238 if( maxscore.auxviol > 0.0 )
    7239 {
    7240 cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
    7241 weightsum += conshdlrdata->branchviolweight;
    7242
    7243 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
    7244 }
    7245
    7246 if( maxscore.fractionality > 0.0 )
    7247 {
    7248 cands[c].weighted += conshdlrdata->branchfracweight * cands[c].fractionality / maxscore.fractionality;
    7249 weightsum += conshdlrdata->branchfracweight;
    7250
    7251 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(frac)", conshdlrdata->branchfracweight, cands[c].fractionality / maxscore.fractionality); )
    7252 }
    7253
    7254 if( maxscore.domain > 0.0 )
    7255 {
    7256 cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
    7257 weightsum += conshdlrdata->branchdomainweight;
    7258
    7259 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
    7260 }
    7261
    7262 if( maxscore.dual > 0.0 )
    7263 {
    7264 cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
    7265 weightsum += conshdlrdata->branchdualweight;
    7266
    7267 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
    7268 }
    7269
    7270 if( maxscore.pscost > 0.0 )
    7271 {
    7272 /* use pseudo-costs only if available */
    7273 if( cands[c].pscost != SCIP_INVALID )
    7274 {
    7275 cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
    7276 weightsum += conshdlrdata->branchpscostweight;
    7277
    7278 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
    7279 }
    7280 else
    7281 {
    7282 /* do not add pscostscore, if not available, also do not add into weightsum */
    7283 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
    7284 }
    7285 }
    7286
    7287 if( maxscore.vartype > 0.0 )
    7288 {
    7289 cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
    7290 weightsum += conshdlrdata->branchvartypeweight;
    7291
    7292 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
    7293 }
    7294
    7295 assert(weightsum > 0.0); /* we should have got at least one valid score */
    7296 cands[c].weighted /= weightsum;
    7297
    7298 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
    7299 }
    7300}
    7301
    7302/** compare two branching candidates by their weighted score
    7303 *
    7304 * if weighted score is equal, use variable index of (aux)var
    7305 * if variables are the same, then use whether variable was added due to nonlinearity or fractionality
    7306 */
    7307static
    7308SCIP_DECL_SORTINDCOMP(branchcandCompare)
    7309{
    7310 BRANCHCAND* cands = (BRANCHCAND*)dataptr;
    7311
    7312 if( cands[ind1].weighted != cands[ind2].weighted )
    7313 return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
    7314
    7315 if( cands[ind1].var != cands[ind2].var )
    7316 return SCIPvarGetIndex(cands[ind1].var) - SCIPvarGetIndex(cands[ind2].var);
    7317
    7318 return cands[ind1].expr != NULL ? 1 : -1;
    7319}
    7320
    7321/** picks a candidate from array of branching candidates */
    7322static
    7324 SCIP* scip, /**< SCIP data structure */
    7325 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7326 BRANCHCAND* cands, /**< branching candidates */
    7327 int ncands, /**< number of candidates */
    7328 SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
    7329 SCIP_SOL* sol, /**< relaxation solution, NULL for LP */
    7330 BRANCHCAND** selected /**< buffer to store selected branching candidates */
    7331 )
    7332{
    7333 SCIP_CONSHDLRDATA* conshdlrdata;
    7334 int* perm;
    7335 int c;
    7336 int left;
    7337 int right;
    7338 SCIP_Real threshold;
    7339
    7340 assert(cands != NULL);
    7341 assert(ncands >= 1);
    7342 assert(selected != NULL);
    7343
    7344 if( ncands == 1 )
    7345 {
    7346 *selected = cands;
    7347 return SCIP_OKAY;
    7348 }
    7349
    7350 /* if there are more than one candidate, then compute scores and select */
    7351
    7352 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7353 assert(conshdlrdata != NULL);
    7354
    7355 /* compute additional scores on branching candidates and weighted score */
    7356 scoreBranchingCandidates(scip, conshdlr, cands, ncands, considerfracnl, sol);
    7357
    7358 /* sort candidates by weighted score */
    7359 SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
    7360 SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
    7361
    7362 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
    7363 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
    7364 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
    7365
    7366 /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
    7367 left = 0;
    7368 right = ncands - 1;
    7369 threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
    7370 while( left < right )
    7371 {
    7372 int mid = (left + right) / 2;
    7373 if( cands[perm[mid]].weighted >= threshold )
    7374 left = mid + 1;
    7375 else
    7376 right = mid;
    7377 }
    7378 assert(left <= ncands);
    7379
    7380 if( left < ncands )
    7381 {
    7382 if( cands[perm[left]].weighted >= threshold )
    7383 {
    7384 assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
    7385 ncands = left + 1;
    7386 }
    7387 else
    7388 {
    7389 assert(cands[perm[left]].weighted < threshold);
    7390 ncands = left;
    7391 }
    7392 }
    7393 assert(ncands > 0);
    7394
    7395 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
    7396 SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
    7397 SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
    7398
    7399 if( ncands > 1 )
    7400 {
    7401 /* choose at random from candidates 0..ncands-1 */
    7402 if( conshdlrdata->branchrandnumgen == NULL )
    7403 {
    7404 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
    7405 }
    7406 c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
    7407 *selected = &cands[perm[c]];
    7408 }
    7409 else
    7410 *selected = &cands[perm[0]];
    7411
    7412 SCIPfreeBufferArray(scip, &perm);
    7413
    7414 return SCIP_OKAY;
    7415}
    7416
    7417/** do spatial branching or register branching candidates */
    7418static
    7420 SCIP* scip, /**< SCIP data structure */
    7421 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7422 SCIP_CONS** conss, /**< constraints to process */
    7423 int nconss, /**< number of constraints */
    7424 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
    7425 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    7426 SCIP_Longint soltag, /**< tag of solution */
    7427 SCIP_RESULT* result /**< pointer to store the result of branching */
    7428 )
    7429{
    7430 SCIP_CONSHDLRDATA* conshdlrdata;
    7431 BRANCHCAND* cands;
    7432 int ncands;
    7433 BRANCHCAND* selected = NULL;
    7434 SCIP_NODE* downchild;
    7435 SCIP_NODE* eqchild;
    7436 SCIP_NODE* upchild;
    7437
    7438 assert(conshdlr != NULL);
    7439 assert(result != NULL);
    7440
    7441 *result = SCIP_DIDNOTFIND;
    7442
    7443 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7444 assert(conshdlrdata != NULL);
    7445
    7446 if( conshdlrdata->branchexternal )
    7447 {
    7448 /* just register branching candidates as external */
    7449 SCIP_Bool success;
    7450
    7451 SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
    7452 if( success )
    7453 *result = SCIP_INFEASIBLE;
    7454
    7455 return SCIP_OKAY;
    7456 }
    7457
    7458 /* collect branching candidates and their auxviol-score */
    7460 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
    7461
    7462 /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
    7463 * we will return here and let the fallbacks in consEnfo() decide how to proceed
    7464 */
    7465 if( ncands == 0 )
    7466 goto TERMINATE;
    7467
    7468 /* here we include fractionality of integer variables into the branching score
    7469 * but if we know there will be no fractional integer variables, then we can shortcut and turn this off
    7470 */
    7471 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, sol == NULL && SCIPgetNLPBranchCands(scip) > 0, sol, &selected) );
    7472 assert(selected != NULL);
    7473 assert(selected->expr != NULL);
    7474
    7475 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(selected->var),
    7476 SCIPvarGetLbLocal(selected->var), SCIPvarGetUbLocal(selected->var)); )
    7477
    7478 SCIP_CALL( SCIPbranchVarVal(scip, selected->var, SCIPgetBranchingPoint(scip, selected->var, SCIP_INVALID), &downchild, &eqchild,
    7479 &upchild) );
    7480 if( downchild != NULL || eqchild != NULL || upchild != NULL )
    7481 *result = SCIP_BRANCHED;
    7482 else
    7483 /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
    7484 *result = SCIP_REDUCEDDOM;
    7485
    7486 TERMINATE:
    7487 SCIPfreeBufferArray(scip, &cands);
    7488
    7489 return SCIP_OKAY;
    7490}
    7491
    7492/** call enforcement or estimate callback of nonlinear handler
    7493 *
    7494 * Calls the enforcement callback, if available.
    7495 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
    7496 *
    7497 * If cut is weak, but estimator is not tight, tries to add branching candidates.
    7498 */
    7499static
    7501 SCIP* scip, /**< SCIP main data structure */
    7502 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7503 SCIP_CONS* cons, /**< nonlinear constraint */
    7504 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
    7505 SCIP_EXPR* expr, /**< expression */
    7506 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
    7507 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
    7508 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
    7509 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
    7510 SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
    7511 SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
    7512 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
    7513 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
    7514 SCIP_RESULT* result /**< pointer to store the result */
    7515 )
    7516{
    7517 assert(result != NULL);
    7518
    7519 /* call enforcement callback of the nlhdlr */
    7520 SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
    7521 allowweakcuts, separated, inenforcement, branchcandonly, result) );
    7522
    7523 /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
    7524 if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
    7525 {
    7526 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
    7527 SCIPnlhdlrGetName(nlhdlr), *result); )
    7528 return SCIP_OKAY;
    7529 }
    7530 else
    7531 {
    7532 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
    7533 }
    7534
    7535 *result = SCIP_DIDNOTFIND;
    7536
    7537 /* now call the estimator callback of the nlhdlr */
    7538 if( SCIPnlhdlrHasEstimate(nlhdlr) )
    7539 {
    7540 SCIP_VAR* auxvar;
    7541 SCIP_Bool sepasuccess = FALSE;
    7542 SCIP_Bool branchscoresuccess = FALSE;
    7543 SCIP_PTRARRAY* rowpreps;
    7544 int minidx;
    7545 int maxidx;
    7546 int r;
    7547 SCIP_ROWPREP* rowprep;
    7548
    7549 SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
    7550
    7551 auxvar = SCIPgetExprAuxVarNonlinear(expr);
    7552 assert(auxvar != NULL);
    7553
    7554 SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
    7555 SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
    7556
    7557 minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
    7558 maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
    7559
    7560 assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
    7561
    7562 if( !sepasuccess )
    7563 {
    7564 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
    7565 SCIPnlhdlrGetName(nlhdlr)); )
    7566 }
    7567
    7568 for( r = minidx; r <= maxidx; ++r )
    7569 {
    7570 rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
    7571
    7572 assert(rowprep != NULL);
    7573 assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
    7574
    7575 if( !branchcandonly )
    7576 {
    7577 /* complete estimator to cut */
    7578 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
    7579
    7580 /* add the cut and/or branching scores
    7581 * (branching scores that could be added here are to deal with bad numerics of cuts; we skip these if branchcandonly)
    7582 */
    7583 SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
    7584 auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
    7585 }
    7586
    7587 SCIPfreeRowprep(scip, &rowprep);
    7588 }
    7589
    7590 if( branchcandonly && branchscoresuccess )
    7591 {
    7592 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s added branching candidates\n", SCIPnlhdlrGetName(nlhdlr)); )
    7593 *result = SCIP_BRANCHED;
    7594 }
    7595
    7596 SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
    7597 }
    7598
    7599 return SCIP_OKAY;
    7600}
    7601
    7602/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
    7603 *
    7604 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
    7605 */
    7606static
    7608 SCIP* scip, /**< SCIP data structure */
    7609 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
    7610 SCIP_CONS* cons, /**< nonlinear constraint */
    7611 SCIP_EXPR* expr, /**< expression */
    7612 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
    7613 SCIP_Longint soltag, /**< tag of solution */
    7614 SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
    7615 SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
    7616 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
    7617 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    7618 )
    7619{
    7620 SCIP_CONSHDLRDATA* conshdlrdata;
    7621 SCIP_EXPR_OWNERDATA* ownerdata;
    7622 SCIP_Real origviol;
    7623 SCIP_Bool underestimate;
    7624 SCIP_Bool overestimate;
    7625 SCIP_Real auxviol;
    7626 SCIP_Bool auxunderestimate;
    7627 SCIP_Bool auxoverestimate;
    7628 SCIP_RESULT hdlrresult;
    7629 int e;
    7630
    7631 assert(scip != NULL);
    7632 assert(expr != NULL);
    7633 assert(result != NULL);
    7634
    7635 ownerdata = SCIPexprGetOwnerData(expr);
    7636 assert(ownerdata != NULL);
    7637 assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
    7638
    7639 *result = SCIP_DIDNOTFIND;
    7640
    7641 /* make sure that this expression has been evaluated */
    7642 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
    7643
    7644 /* decide whether under- or overestimate is required and get amount of violation */
    7645 origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
    7646
    7647 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7648 assert(conshdlrdata != NULL);
    7649
    7650 /* no sufficient violation w.r.t. the original variables -> skip expression */
    7651 if( !overestimate && !underestimate )
    7652 {
    7653 return SCIP_OKAY;
    7654 }
    7655
    7656 /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
    7657 for( e = 0; e < ownerdata->nenfos; ++e )
    7658 {
    7659 SCIP_NLHDLR* nlhdlr;
    7660
    7661 /* skip nlhdlr that do not want to participate in any separation */
    7662 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
    7663 continue;
    7664
    7665 /* if looking for branching candidates only, then skip nlhdlr that wouldn't created branching candidates */
    7666 if( branchcandonly && !ownerdata->enfos[e]->sepaaboveusesactivity && !ownerdata->enfos[e]->sepabelowusesactivity )
    7667 continue;
    7668
    7669 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    7670 assert(nlhdlr != NULL);
    7671
    7672 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
    7673 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
    7674 ENFOLOG(
    7675 SCIPinfoMessage(scip, enfologfile, " expr ");
    7676 SCIPprintExpr(scip, expr, enfologfile);
    7677 SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
    7678 "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
    7679 SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
    7680 )
    7681
    7682 /* TODO if expr is root of constraint (consdata->expr == expr),
    7683 * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
    7684 * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
    7685 * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
    7686 * so we should enforce in these auxiliaries first
    7687 * if changing this here, we must also adapt analyzeViolation()
    7688 */
    7689
    7690 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
    7691 assert(auxviol >= 0.0);
    7692
    7693 /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
    7694 if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
    7695 {
    7696 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
    7697 "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
    7698 SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
    7699
    7700 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
    7701 continue;
    7702 }
    7703
    7704 /* 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 */
    7705 if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
    7706 {
    7707 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
    7708 "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
    7709 underestimate, overestimate); )
    7710
    7711 /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
    7712 continue;
    7713 }
    7714
    7715 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
    7716 "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
    7717 auxviol, origviol, underestimate, overestimate, allowweakcuts); )
    7718
    7719 /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
    7720 * wants to be called for separation on this side, then call separation of nlhdlr
    7721 */
    7722 if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepaaboveusesactivity) )
    7723 {
    7724 /* call the separation or estimation callback of the nonlinear handler for overestimation */
    7725 hdlrresult = SCIP_DIDNOTFIND;
    7726 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
    7727 ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
    7728
    7729 if( hdlrresult == SCIP_CUTOFF )
    7730 {
    7731 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
    7732 *result = SCIP_CUTOFF;
    7733 ownerdata->lastenforced = conshdlrdata->enforound;
    7734 break;
    7735 }
    7736
    7737 if( hdlrresult == SCIP_SEPARATED )
    7738 {
    7739 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
    7740 *result = SCIP_SEPARATED;
    7741 ownerdata->lastenforced = conshdlrdata->enforound;
    7742 /* TODO or should we give other nlhdlr another chance? (also #3070) */
    7743 break;
    7744 }
    7745
    7746 if( hdlrresult == SCIP_REDUCEDDOM )
    7747 {
    7748 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
    7749 *result = SCIP_REDUCEDDOM;
    7750 ownerdata->lastenforced = conshdlrdata->enforound;
    7751 /* TODO or should we always just stop here? */
    7752 }
    7753
    7754 if( hdlrresult == SCIP_BRANCHED )
    7755 {
    7756 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
    7757 assert(inenforcement);
    7758
    7759 /* separation and domain reduction takes precedence over branching */
    7760 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
    7761 if( *result == SCIP_DIDNOTFIND )
    7762 *result = SCIP_BRANCHED;
    7763 ownerdata->lastenforced = conshdlrdata->enforound;
    7764 }
    7765 }
    7766
    7767 /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
    7768 * wants to be called for separation on this side, then call separation of nlhdlr
    7769 */
    7770 if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepabelowusesactivity) )
    7771 {
    7772 /* call the separation or estimation callback of the nonlinear handler for underestimation */
    7773 hdlrresult = SCIP_DIDNOTFIND;
    7774 SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
    7775 ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
    7776
    7777 if( hdlrresult == SCIP_CUTOFF )
    7778 {
    7779 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
    7780 *result = SCIP_CUTOFF;
    7781 ownerdata->lastenforced = conshdlrdata->enforound;
    7782 break;
    7783 }
    7784
    7785 if( hdlrresult == SCIP_SEPARATED )
    7786 {
    7787 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
    7788 *result = SCIP_SEPARATED;
    7789 ownerdata->lastenforced = conshdlrdata->enforound;
    7790 /* TODO or should we give other nlhdlr another chance? (also #3070) */
    7791 break;
    7792 }
    7793
    7794 if( hdlrresult == SCIP_REDUCEDDOM )
    7795 {
    7796 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
    7797 *result = SCIP_REDUCEDDOM;
    7798 ownerdata->lastenforced = conshdlrdata->enforound;
    7799 /* TODO or should we always just stop here? */
    7800 }
    7801
    7802 if( hdlrresult == SCIP_BRANCHED )
    7803 {
    7804 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
    7805 assert(inenforcement);
    7806
    7807 /* separation takes precedence over branching */
    7808 assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
    7809 if( *result == SCIP_DIDNOTFIND )
    7810 *result = SCIP_BRANCHED;
    7811 ownerdata->lastenforced = conshdlrdata->enforound;
    7812 }
    7813 }
    7814 }
    7815
    7816 return SCIP_OKAY;
    7817}
    7818
    7819/** helper function to enforce a single constraint */
    7820static
    7822 SCIP* scip, /**< SCIP data structure */
    7823 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7824 SCIP_CONS* cons, /**< constraint to process */
    7825 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    7826 SCIP_Longint soltag, /**< tag of solution */
    7827 SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
    7828 SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
    7829 SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
    7830 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
    7831 SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
    7832 SCIP_Bool* success /**< buffer to store whether some enforcement took place */
    7833 )
    7834{
    7835 SCIP_CONSDATA* consdata;
    7836 SCIP_CONSHDLRDATA* conshdlrdata;
    7837 SCIP_EXPR* expr;
    7838
    7839 assert(conshdlr != NULL);
    7840 assert(cons != NULL);
    7841 assert(it != NULL);
    7842 assert(result != NULL);
    7843 assert(success != NULL);
    7844
    7845 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7846 assert(conshdlrdata != NULL);
    7847
    7848 consdata = SCIPconsGetData(cons);
    7849 assert(consdata != NULL);
    7850 assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
    7851
    7852 *success = FALSE;
    7853
    7854 if( inenforcement && !branchcandonly && !consdata->ispropagated )
    7855 {
    7856 /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
    7857 * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
    7858 * (TODO: nlhdlr tells us now whether they do and so we could skip).
    7859 * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
    7860 * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
    7861 * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
    7862 * confuse the stalling check for how long to do separation).
    7863 */
    7864 SCIP_Bool infeasible;
    7865 int ntightenings;
    7866
    7867 SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
    7868 if( infeasible )
    7869 {
    7870 *result = SCIP_CUTOFF;
    7871 return SCIP_OKAY;
    7872 }
    7873 /* if we tightened an auxvar bound, we better communicate that */
    7874 if( ntightenings > 0 )
    7875 *result = SCIP_REDUCEDDOM;
    7876 }
    7877
    7878 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    7879 {
    7880 SCIP_EXPR_OWNERDATA* ownerdata;
    7881 SCIP_RESULT resultexpr;
    7882
    7883 ownerdata = SCIPexprGetOwnerData(expr);
    7884 assert(ownerdata != NULL);
    7885
    7886 /* we can only enforce if there is an auxvar to compare with */
    7887 if( ownerdata->auxvar == NULL )
    7888 continue;
    7889
    7890 assert(ownerdata->lastenforced <= conshdlrdata->enforound);
    7891 if( ownerdata->lastenforced == conshdlrdata->enforound )
    7892 {
    7893 ENFOLOG(
    7894 SCIPinfoMessage(scip, enfologfile, " skip expr ");
    7895 SCIPprintExpr(scip, expr, enfologfile);
    7896 SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
    7897 )
    7898 *success = TRUE;
    7899 continue;
    7900 }
    7901
    7902 SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, branchcandonly, &resultexpr) );
    7903
    7904 /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
    7905 assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
    7906 if( ownerdata->lastenforced == conshdlrdata->enforound ) /* cppcheck-suppress knownConditionTrueFalse */
    7907 *success = TRUE;
    7908
    7909 if( resultexpr == SCIP_CUTOFF )
    7910 {
    7911 *result = SCIP_CUTOFF;
    7912 break;
    7913 }
    7914
    7915 if( resultexpr == SCIP_SEPARATED )
    7916 *result = SCIP_SEPARATED;
    7917
    7918 if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
    7919 *result = SCIP_REDUCEDDOM;
    7920
    7921 if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
    7922 *result = SCIP_BRANCHED;
    7923 }
    7924
    7925 return SCIP_OKAY;
    7926}
    7927
    7928/** try to separate violated constraints and, if in enforcement, register branching scores
    7929 *
    7930 * If branchcandonly=TRUE, then do not separate or propagate, but register branching scores only.
    7931 *
    7932 * Sets result to
    7933 * - SCIP_DIDNOTFIND, if nothing of the below has been done
    7934 * - SCIP_CUTOFF, if node can be cutoff,
    7935 * - SCIP_SEPARATED, if a cut has been added,
    7936 * - SCIP_REDUCEDDOM, if a domain reduction has been found or a variable got fixed (in an attempt to branch on it),
    7937 * - SCIP_BRANCHED, if branching has been done (if branchcandonly=TRUE, then collected branching candidates only),
    7938 * - SCIP_INFEASIBLE, if external branching candidates were registered
    7939 */
    7940static
    7942 SCIP* scip, /**< SCIP data structure */
    7943 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    7944 SCIP_CONS** conss, /**< constraints to process */
    7945 int nconss, /**< number of constraints */
    7946 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    7947 SCIP_Longint soltag, /**< tag of solution */
    7948 SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
    7949 SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
    7950 SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
    7951 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    7952 )
    7953{
    7954 SCIP_CONSHDLRDATA* conshdlrdata;
    7955 SCIP_EXPRITER* it;
    7956 SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
    7957 int c;
    7958
    7959 assert(conshdlr != NULL);
    7960 assert(conss != NULL || nconss == 0);
    7961 assert(result != NULL);
    7962
    7963 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    7964 assert(conshdlrdata != NULL);
    7965
    7966 /* increase tag to tell whether branching scores in expression belong to this sweep
    7967 * and which expressions have already been enforced in this sweep
    7968 * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
    7969 */
    7970 ++(conshdlrdata->enforound);
    7971
    7972 *result = SCIP_DIDNOTFIND;
    7973
    7976
    7977 for( c = 0; c < nconss; ++c )
    7978 {
    7979 assert(conss != NULL && conss[c] != NULL);
    7980
    7981 /* skip constraints that are not enabled or deleted */
    7982 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
    7983 continue;
    7984 assert(SCIPconsIsActive(conss[c]));
    7985
    7986 /* skip constraints that have separation disabled if we are only in separation */
    7987 if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
    7988 continue;
    7989
    7990 /* skip non-violated constraints */
    7991 if( !isConsViolated(scip, conss[c]) )
    7992 continue;
    7993
    7994 ENFOLOG(
    7995 {
    7996 SCIP_CONSDATA* consdata;
    7997 int i;
    7998 consdata = SCIPconsGetData(conss[c]);
    7999 assert(consdata != NULL);
    8000 SCIPinfoMessage(scip, enfologfile, " constraint ");
    8001 SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
    8002 SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
    8003 for( i = 0; i < consdata->nvarexprs; ++i )
    8004 {
    8005 SCIP_VAR* var;
    8006 var = SCIPgetVarExprVar(consdata->varexprs[i]);
    8007 SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
    8008 SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
    8009 }
    8010 })
    8011
    8012 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, branchcandonly, result, &consenforced) );
    8013
    8014 if( *result == SCIP_CUTOFF )
    8015 break;
    8016
    8017 if( !consenforced && inenforcement && !branchcandonly )
    8018 {
    8019 SCIP_Real viol;
    8020
    8021 SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
    8022 if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
    8023 {
    8024 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
    8025 "cuts allowed\n", SCIPconsGetName(conss[c])); )
    8026
    8027 SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, branchcandonly, result, &consenforced) );
    8028
    8029 if( consenforced )
    8030 ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
    8031
    8032 if( *result == SCIP_CUTOFF )
    8033 break;
    8034 }
    8035 }
    8036 }
    8037
    8038 SCIPfreeExpriter(&it);
    8039
    8040 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
    8041
    8042 if( *result == SCIP_BRANCHED && !branchcandonly )
    8043 {
    8044 /* having result set to branched here means only that we have branching candidates, we still need to do the actual
    8045 * branching
    8046 */
    8047 SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
    8048
    8049 /* branching should either have branched: result == SCIP_BRANCHED,
    8050 * or fixed a variable: result == SCIP_REDUCEDDOM,
    8051 * or have registered external branching candidates: result == SCIP_INFEASIBLE,
    8052 * or have not done anything: result == SCIP_DIDNOTFIND
    8053 */
    8054 assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
    8055 }
    8056
    8057 ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
    8058
    8059 return SCIP_OKAY;
    8060}
    8061
    8062/** decide whether to branch on fractional integer or nonlinear variable
    8063 *
    8064 * The routine collects spatial branching candidates by a call to enforceConstraints(branchcandonly=TRUE)
    8065 * and collectBranchingCandidates(). Then it adds fractional integer variables to the candidate list.
    8066 * Variables that are candidate for both spatial branching and fractionality are considered as two separate candidates.
    8067 * selectBranchingCandidate() then selects a variable for branching from the joined candidate list.
    8068 * If the selected variable is a fractional integer one, then branchintegral=TRUE is returned, otherwise FALSE.
    8069 * Some shortcuts exist for cases where there are no candidates of the one kind or the other.
    8070 */
    8071static
    8073 SCIP* scip, /**< SCIP data structure */
    8074 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8075 SCIP_CONS** conss, /**< constraints to process */
    8076 int nconss, /**< number of constraints */
    8077 SCIP_Longint soltag, /**< tag of LP solution */
    8078 SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
    8079 SCIP_Bool* branchintegral, /**< buffer to store whether to branch on fractional integer variables first */
    8080 SCIP_Bool* cutoff /**< buffer to store whether infeasibility has been detected */
    8081 )
    8082{
    8083 SCIP_RESULT result;
    8084 int nlpcands;
    8085 SCIP_VAR** lpcands; /* fractional integer variables */
    8086 SCIP_Real* lpcandsfrac; /* fractionalities */
    8087 BRANCHCAND* cands;
    8088 BRANCHCAND* selected;
    8089 int ncands;
    8090 int c;
    8091
    8092 assert(scip != NULL);
    8093 assert(conshdlr != NULL);
    8094 assert(conss != NULL);
    8095 assert(nconss > 0);
    8096 assert(branchintegral != NULL);
    8097 assert(cutoff != NULL);
    8098
    8099 *branchintegral = FALSE;
    8100 *cutoff = FALSE;
    8101
    8103 return SCIP_OKAY;
    8104
    8105 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, NULL, (SCIP_Longint)0, TRUE, TRUE, maxrelconsviol, &result) );
    8106 switch( result )
    8107 {
    8108 case SCIP_DIDNOTFIND:
    8109 /* no branching candidates found could mean that the LP solution is in a convex region */
    8110 *branchintegral = TRUE;
    8111 return SCIP_OKAY;
    8112
    8113 case SCIP_CUTOFF:
    8114 /* probably cannot happen, but easy to handle */
    8115 *cutoff = TRUE;
    8116 return SCIP_OKAY;
    8117
    8118 case SCIP_SEPARATED:
    8119 case SCIP_REDUCEDDOM:
    8120 /* we asked enforceConstraints() to collect branching candidates only, it shouldn't have separated or propagated */
    8121 SCIPerrorMessage("Unexpected separation or propagation from enforceConstraints(branchcandonly = TRUE)\n");
    8122 return SCIP_ERROR;
    8123
    8124 case SCIP_BRANCHED:
    8125 /* actually meaning that branching candidates were registered (the result for which we have gone through all this effort) */
    8126 break;
    8127
    8128 case SCIP_INFEASIBLE:
    8129 /* should not happen (enforceConstraints() returns this if external branching candidates were registered in branching(),
    8130 * but this was disabled by branchcandonly = TRUE)
    8131 */
    8132 default:
    8133 SCIPerrorMessage("Unexpected return from enforceConstraints(branchcandonly = TRUE)\n");
    8134 return SCIP_ERROR;
    8135 } /*lint !e788*/
    8136
    8137 /* collect spatial branching candidates and their auxviol-score */
    8139 SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, NULL, soltag, cands, &ncands) );
    8140
    8141 /* add fractional integer variables to branching candidates */
    8142 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) );
    8143
    8144 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding %d fractional integer variables to branching candidates\n", nlpcands); )
    8145
    8146 for( c = 0; c < nlpcands; ++c )
    8147 {
    8148 assert(SCIPvarGetType(lpcands[c]) != SCIP_VARTYPE_CONTINUOUS);
    8149 assert(ncands < SCIPgetNVars(scip) + SCIPgetNLPBranchCands(scip));
    8150 cands[ncands].expr = NULL;
    8151 cands[ncands].var = lpcands[c];
    8152 cands[ncands].auxviol = 0.0;
    8153 cands[ncands].fractionality = lpcandsfrac[c];
    8154 ++ncands;
    8155 }
    8156
    8157 /* select a variable for branching
    8158 * to keep things separate, do not include fractionality of integer variables into scores of spatial branching candidates
    8159 * the same variables appear among the candidates for branching on integrality, where its fractionality is considered
    8160 */
    8161 SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, FALSE, NULL, &selected) );
    8162 assert(selected != NULL);
    8163
    8164 if( selected->expr == NULL )
    8165 {
    8166 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " fractional variable <%s> selected for branching; fall back to cons_integral\n", SCIPvarGetName(selected->var)); )
    8167
    8168 *branchintegral = TRUE;
    8169 }
    8170
    8171 SCIPfreeBufferArray(scip, &cands);
    8172
    8173 return SCIP_OKAY;
    8174}
    8175
    8176/** decide whether to consider spatial branching before integrality has been enforced
    8177 *
    8178 * This decides whether we are still at a phase where we always want to branch on fractional integer variables if any (return TRUE),
    8179 * or whether branchingIntegralOrNonlinear() should be used (return FALSE).
    8180 *
    8181 * This essentially checks whether the average pseudo cost count exceeds the value of parameter branchmixfractional.
    8182 */
    8183static
    8185 SCIP* scip, /**< SCIP data structure */
    8186 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8187 SCIP_SOL* sol /**< solution to be enforced */
    8188 )
    8189{
    8190 SCIP_CONSHDLRDATA* conshdlrdata;
    8191
    8192 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8193 assert(conshdlrdata != NULL);
    8194
    8195 /* if LP still unbounded, then work on nonlinear constraints first */
    8197 return FALSE;
    8198
    8199 /* no branching in cons_integral if no integer variables */
    8201 return FALSE;
    8202
    8203 /* no branching in cons_integral if LP solution not fractional */
    8204 if( sol == NULL && SCIPgetNLPBranchCands(scip) == 0 )
    8205 return FALSE;
    8206
    8207 /* no branching in cons_integral if relax solution not fractional */
    8208 if( sol != NULL )
    8209 {
    8210 SCIP_Bool isfractional = FALSE;
    8211 SCIP_VAR** vars;
    8212 int nbinvars;
    8213 int nintvars;
    8214 int i;
    8215
    8216 vars = SCIPgetVars(scip);
    8217 nbinvars = SCIPgetNBinVars(scip);
    8218 nintvars = SCIPgetNIntVars(scip);
    8219
    8220 for( i = 0; i < nbinvars + nintvars && !isfractional; ++i )
    8221 {
    8222 assert(vars[i] != NULL);
    8223 assert(SCIPvarIsIntegral(vars[i]));
    8224
    8225 if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[i])) )
    8226 isfractional = TRUE;
    8227 }
    8228
    8229 if( !isfractional )
    8230 return FALSE;
    8231 }
    8232
    8233 /* branchmixfractional being infinity means that integral should always go first */
    8234 if( SCIPisInfinity(scip, conshdlrdata->branchmixfractional) )
    8235 return TRUE;
    8236
    8237 /* branchmixfractional being 0.0 means we do not wait for any pseudocosts to be available */
    8238 if( conshdlrdata->branchmixfractional == 0.0 )
    8239 return FALSE;
    8240
    8241 /* if not yet enough pseudocosts for down or up direction, then branch on fractionality
    8242 * @todo this gives the total pseudocost count divided by the number of discrete variables
    8243 * if we updated pseudocost after branching on continuous variables, wouldn't this be incorrect? (#3637)
    8244 */
    8245 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_DOWNWARDS) < conshdlrdata->branchmixfractional )
    8246 return TRUE;
    8247 if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_UPWARDS) < conshdlrdata->branchmixfractional )
    8248 return TRUE;
    8249
    8250 /* we may have decent pseudocosts, so go for rule that chooses between fractional and spatial branching based on candidates */
    8251 return FALSE;
    8252}
    8253
    8254/** collect (and print (if debugging enfo)) information on violation in expressions
    8255 *
    8256 * assumes that constraint violations have been computed
    8257 */
    8258static
    8260 SCIP* scip, /**< SCIP data structure */
    8261 SCIP_CONS** conss, /**< constraints */
    8262 int nconss, /**< number of constraints */
    8263 SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
    8264 SCIP_Longint soltag, /**< tag of solution */
    8265 SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
    8266 SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
    8267 SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
    8268 SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
    8269 SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
    8270 )
    8271{
    8272 SCIP_CONSDATA* consdata;
    8273 SCIP_EXPRITER* it;
    8274 SCIP_EXPR* expr;
    8275 SCIP_Real v;
    8276 int c;
    8277
    8278 assert(conss != NULL || nconss == 0);
    8279 assert(maxabsconsviol != NULL);
    8280 assert(maxrelconsviol != NULL);
    8281 assert(maxauxviol != NULL);
    8282 assert(maxvarboundviol != NULL);
    8283
    8286
    8287 *maxabsconsviol = 0.0;
    8288 *maxrelconsviol = 0.0;
    8289 *minauxviol = SCIPinfinity(scip);
    8290 *maxauxviol = 0.0;
    8291 *maxvarboundviol = 0.0;
    8292
    8293 for( c = 0; c < nconss; ++c )
    8294 {
    8295 assert(conss != NULL && conss[c] != NULL);
    8296
    8297 consdata = SCIPconsGetData(conss[c]);
    8298 assert(consdata != NULL);
    8299
    8300 /* skip constraints that are not enabled, deleted, or have separation disabled */
    8301 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
    8302 continue;
    8303 assert(SCIPconsIsActive(conss[c]));
    8304
    8305 v = getConsAbsViolation(conss[c]);
    8306 *maxabsconsviol = MAX(*maxabsconsviol, v);
    8307
    8308 /* skip non-violated constraints */
    8309 if( !isConsViolated(scip, conss[c]) )
    8310 continue;
    8311
    8312 SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
    8313 *maxrelconsviol = MAX(*maxrelconsviol, v);
    8314
    8315 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    8316 {
    8317 SCIP_EXPR_OWNERDATA* ownerdata;
    8318 SCIP_Real auxvarvalue;
    8319 SCIP_Real auxvarlb;
    8320 SCIP_Real auxvarub;
    8321 SCIP_Bool violunder;
    8322 SCIP_Bool violover;
    8323 SCIP_Real origviol;
    8324 SCIP_Real auxviol;
    8325 int e;
    8326
    8327 ownerdata = SCIPexprGetOwnerData(expr);
    8328 assert(ownerdata != NULL);
    8329
    8330 if( ownerdata->auxvar == NULL )
    8331 {
    8332 /* check violation of variable bounds of original variable */
    8333 if( SCIPisExprVar(scip, expr) )
    8334 {
    8335 SCIP_VAR* var;
    8336 var = SCIPgetVarExprVar(expr);
    8337 auxvarvalue = SCIPgetSolVal(scip, sol, var);
    8338 auxvarlb = SCIPvarGetLbLocal(var);
    8339 auxvarub = SCIPvarGetUbLocal(var);
    8340
    8341 origviol = 0.0;
    8342 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
    8343 origviol = auxvarlb - auxvarvalue;
    8344 else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
    8345 origviol = auxvarvalue - auxvarub;
    8346 if( origviol <= 0.0 )
    8347 continue;
    8348
    8349 *maxvarboundviol = MAX(*maxvarboundviol, origviol);
    8350
    8351 ENFOLOG(
    8352 SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
    8353 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
    8354 SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
    8355 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
    8356 SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
    8357 SCIPinfoMessage(scip, enfologfile, "\n");
    8358 )
    8359 }
    8360
    8361 continue;
    8362 }
    8363
    8364 auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
    8365 auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
    8366 auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
    8367
    8368 /* check violation of variable bounds of auxiliary variable */
    8369 if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
    8370 *maxvarboundviol = auxvarlb - auxvarvalue;
    8371 else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
    8372 *maxvarboundviol = auxvarvalue - auxvarub;
    8373
    8374 origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
    8375
    8376 ENFOLOG(
    8377 if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
    8378 {
    8379 SCIPinfoMessage(scip, enfologfile, "expr ");
    8380 SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
    8381 SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
    8382
    8383 SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
    8384 if( origviol > 0.0 )
    8385 SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
    8386 if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
    8387 SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
    8388 if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
    8389 SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
    8390 SCIPinfoMessage(scip, enfologfile, "\n");
    8391 }
    8392 )
    8393
    8394 /* no violation w.r.t. the original variables -> skip expression */
    8395 if( origviol == 0.0 )
    8396 continue;
    8397
    8398 /* compute aux-violation for each nonlinear handlers */
    8399 for( e = 0; e < ownerdata->nenfos; ++e )
    8400 {
    8401 SCIP_NLHDLR* nlhdlr;
    8402
    8403 /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
    8404 if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
    8405 continue;
    8406
    8407 nlhdlr = ownerdata->enfos[e]->nlhdlr;
    8408 assert(nlhdlr != NULL);
    8409
    8410 /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
    8411 SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
    8412
    8413 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
    8414
    8415 auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
    8416
    8417 if( auxviol > 0.0 )
    8418 {
    8419 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
    8420 *maxauxviol = MAX(*maxauxviol, auxviol);
    8421 *minauxviol = MIN(*minauxviol, auxviol);
    8422 }
    8423 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
    8424 }
    8425 }
    8426 }
    8427
    8428 SCIPfreeExpriter(&it);
    8429
    8430 return SCIP_OKAY;
    8431} /*lint !e715*/
    8432
    8433/** enforcement of constraints called by enfolp and enforelax */
    8434static
    8436 SCIP* scip, /**< SCIP data structure */
    8437 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8438 SCIP_CONS** conss, /**< constraints to process */
    8439 int nconss, /**< number of constraints */
    8440 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    8441 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    8442 )
    8443{
    8444 SCIP_CONSHDLRDATA* conshdlrdata;
    8445 SCIP_Real maxabsconsviol;
    8446 SCIP_Real maxrelconsviol;
    8447 SCIP_Real minauxviol;
    8448 SCIP_Real maxauxviol;
    8449 SCIP_Real maxvarboundviol;
    8450 SCIP_Longint soltag;
    8451 SCIP_Bool branchintegral;
    8452 int nnotify;
    8453 int c;
    8454
    8455 if( branchingIntegralFirst(scip, conshdlr, sol) )
    8456 {
    8457 /* let cons_integral handle enforcement */
    8458 *result = SCIP_INFEASIBLE;
    8459 return SCIP_OKAY;
    8460 }
    8461
    8462 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8463 assert(conshdlr != NULL);
    8464
    8465 soltag = SCIPgetExprNewSoltag(scip);
    8466
    8467 *result = SCIP_FEASIBLE;
    8468 for( c = 0; c < nconss; ++c )
    8469 {
    8470 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
    8471
    8472 if( isConsViolated(scip, conss[c]) )
    8473 *result = SCIP_INFEASIBLE;
    8474 }
    8475
    8476 if( *result == SCIP_FEASIBLE )
    8477 {
    8478 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
    8480 return SCIP_OKAY;
    8481 }
    8482
    8483 SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
    8484 &minauxviol, &maxauxviol, &maxvarboundviol) );
    8485
    8486 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
    8487 "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
    8488 SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
    8489 maxvarboundviol, SCIPgetLPFeastol(scip)); )
    8490
    8491 assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
    8492
    8493 /* look at fractional and nonlinear branching candidates and decide whether to branch on fractional vars, first */
    8494 if( sol == NULL )
    8495 {
    8496 SCIP_Bool cutoff;
    8497
    8498 SCIP_CALL( branchingIntegralOrNonlinear(scip, conshdlr, conss, nconss, soltag, maxrelconsviol, &branchintegral, &cutoff) );
    8499 if( cutoff )
    8500 {
    8501 *result = SCIP_CUTOFF;
    8502 return SCIP_OKAY;
    8503 }
    8504 if( branchintegral )
    8505 {
    8506 /* let cons_integral handle enforcement */
    8507 *result = SCIP_INFEASIBLE;
    8508 return SCIP_OKAY;
    8509 }
    8510 }
    8511
    8512 /* try to propagate */
    8513 if( conshdlrdata->propinenforce )
    8514 {
    8515 SCIP_RESULT propresult;
    8516 int nchgbds = 0;
    8517
    8518 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
    8519
    8520 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
    8521 {
    8522 *result = propresult;
    8523 return SCIP_OKAY;
    8524 }
    8525 }
    8526
    8527 /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
    8528 * all violated expr/auxvar in violated constraints)
    8529 */
    8530 if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
    8531 sol == NULL )
    8532 {
    8533 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
    8534 ++conshdlrdata->ntightenlp;
    8535
    8536 *result = SCIP_SOLVELP;
    8537
    8538 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
    8539 "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
    8540
    8541 return SCIP_OKAY;
    8542 }
    8543
    8544 /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
    8545 * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
    8546 */
    8547 if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
    8548 {
    8549 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
    8550 ++conshdlrdata->ntightenlp;
    8551
    8552 *result = SCIP_SOLVELP;
    8553
    8554 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
    8555
    8556 return SCIP_OKAY;
    8557 }
    8558
    8559 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, FALSE, maxrelconsviol, result) );
    8560
    8561 if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
    8562 *result == SCIP_INFEASIBLE )
    8563 return SCIP_OKAY;
    8564
    8565 assert(*result == SCIP_DIDNOTFIND);
    8566
    8567 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
    8568 "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
    8569
    8570 if( sol == NULL && SCIPgetNLPBranchCands(scip) > 0 )
    8571 {
    8572 /* if there are still fractional integer variables, then let cons_integral go first */
    8573 *result = SCIP_INFEASIBLE;
    8574 return SCIP_OKAY;
    8575 }
    8576
    8577 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
    8578 {
    8579 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
    8580 ++conshdlrdata->ntightenlp;
    8581
    8582 *result = SCIP_SOLVELP;
    8583
    8584 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
    8585 "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
    8586
    8587 return SCIP_OKAY;
    8588 }
    8589
    8590 if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
    8591 SCIPgetLPFeastol(scip)) && sol == NULL )
    8592 {
    8593 /* try whether tighten the LP feasibility tolerance could help
    8594 * maybe it is just some cut that hasn't been taken into account sufficiently
    8595 * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
    8596 * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
    8597 * until the LP feastol reaches epsilon
    8598 * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
    8599 * when maxauxviol is above LP feastol)
    8600 */
    8601 SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
    8602 ++conshdlrdata->ndesperatetightenlp;
    8603
    8604 *result = SCIP_SOLVELP;
    8605
    8606 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
    8607
    8608 return SCIP_OKAY;
    8609 }
    8610
    8611 /* try to propagate, if not tried above TODO(?) allow to disable this as well */
    8612 if( !conshdlrdata->propinenforce )
    8613 {
    8614 SCIP_RESULT propresult;
    8615 int nchgbds = 0;
    8616
    8617 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
    8618
    8619 if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
    8620 {
    8621 *result = propresult;
    8622 return SCIP_OKAY;
    8623 }
    8624 }
    8625
    8626 /* could not find branching candidates even when looking at minimal violated (>eps) expressions
    8627 * now look if we find any unfixed variable that we could still branch on
    8628 */
    8629 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
    8630
    8631 if( nnotify > 0 )
    8632 {
    8633 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
    8634 ++conshdlrdata->ndesperatebranch;
    8635
    8636 *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
    8637
    8638 return SCIP_OKAY;
    8639 }
    8640
    8641 /* if everything is fixed in violated constraints, then let's cut off the node
    8642 * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
    8643 * result may not be conclusive (when constraint violations are small)
    8644 * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
    8645 * sufficiently (see st_e40)
    8646 * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
    8647 * not "desperate", but a pretty obvious thing to do
    8648 */
    8649 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
    8650 *result = SCIP_CUTOFF;
    8651
    8652 /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
    8653 if( !SCIPisZero(scip, maxvarboundviol) )
    8654 ++conshdlrdata->ndesperatecutoff;
    8655
    8656 return SCIP_OKAY;
    8657}
    8658
    8659/** separation for all violated constraints to be used by SEPA callbacks */
    8660static
    8662 SCIP* scip, /**< SCIP data structure */
    8663 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8664 SCIP_CONS** conss, /**< constraints to process */
    8665 int nconss, /**< number of constraints */
    8666 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
    8667 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
    8668 )
    8669{
    8670 SCIP_Longint soltag;
    8671 SCIP_Bool haveviol = FALSE;
    8672 int c;
    8673
    8674 *result = SCIP_DIDNOTFIND;
    8675
    8676 soltag = SCIPgetExprNewSoltag(scip);
    8677
    8678 /* compute violations */
    8679 for( c = 0; c < nconss; ++c )
    8680 {
    8681 assert(conss[c] != NULL);
    8682
    8683 /* skip constraints that are not enabled, deleted, or have separation disabled */
    8684 if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
    8685 continue;
    8686 assert(SCIPconsIsActive(conss[c]));
    8687
    8688 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
    8689
    8690 if( isConsViolated(scip, conss[c]) )
    8691 haveviol = TRUE;
    8692 }
    8693
    8694 /* if none of our constraints are violated, don't attempt separation */
    8695 if( !haveviol )
    8696 {
    8697 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
    8698 return SCIP_OKAY;
    8699 }
    8700
    8701 ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
    8702
    8703 /* call separation */
    8704 SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, FALSE, SCIP_INVALID, result) );
    8705
    8706 return SCIP_OKAY;
    8707}
    8708
    8709/** hash key retrieval function for bilinear term entries */
    8710static
    8711SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
    8712{ /*lint --e{715}*/
    8713 SCIP_CONSHDLRDATA* conshdlrdata;
    8714 int idx;
    8715
    8716 conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
    8717 assert(conshdlrdata != NULL);
    8718
    8719 idx = ((int)(size_t)elem) - 1;
    8720 assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
    8721
    8722 return (void*)&conshdlrdata->bilinterms[idx];
    8723}
    8724
    8725/** returns TRUE iff the bilinear term entries are equal */
    8726static
    8727SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
    8728{ /*lint --e{715}*/
    8731
    8732 /* get corresponding entries */
    8733 entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
    8734 entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
    8735 assert(entry1->x != NULL && entry1->y != NULL);
    8736 assert(entry2->x != NULL && entry2->y != NULL);
    8737 assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
    8738 assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
    8739
    8740 return entry1->x == entry2->x && entry1->y == entry2->y;
    8741}
    8742
    8743/** returns the hash value of the key */
    8744static
    8745SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
    8746{ /*lint --e{715}*/
    8748
    8749 entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
    8750 assert(entry->x != NULL && entry->y != NULL);
    8751 assert(SCIPvarCompare(entry->x, entry->y) < 1);
    8752
    8753 return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
    8754}
    8755
    8756/** compare two auxiliary expressions
    8757 *
    8758 * Compares auxiliary variables, followed by coefficients, and then constants.
    8759 */
    8760static
    8762{
    8765 int compvars;
    8766 int i;
    8767
    8768 /* compare the auxiliary variables */
    8769 compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
    8770
    8771 if( compvars != 0 )
    8772 return compvars;
    8773
    8774 /* compare the coefficients and constants */
    8775 for( i = 0; i < 3; ++i )
    8776 {
    8777 if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
    8778 return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
    8779 }
    8780
    8781 return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
    8782}
    8783
    8784/* add an auxiliary expression to a bilinear term */
    8785static
    8787 SCIP* scip, /**< SCIP data structure */
    8788 SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
    8789 SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
    8790 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
    8791 SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
    8792 )
    8793{
    8794 SCIP_Bool found;
    8795 int pos;
    8796 int i;
    8797
    8798 *added = FALSE;
    8799
    8800 /* check if auxexpr has already been added to term */
    8801 if( term->nauxexprs == 0 )
    8802 {
    8803 found = FALSE;
    8804 pos = 0;
    8805 }
    8806 else
    8807 {
    8808 found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
    8809 }
    8810
    8811 if( !found )
    8812 {
    8813 if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
    8814 return SCIP_OKAY;
    8815
    8817 assert(term->auxexprssize >= term->nauxexprs + 1);
    8818
    8819 /* insert expression at the correct position */
    8820 for( i = term->nauxexprs; i > pos; --i )
    8821 {
    8822 term->aux.exprs[i] = term->aux.exprs[i-1];
    8823 }
    8824 term->aux.exprs[pos] = auxexpr;
    8825 ++(term->nauxexprs);
    8826 *added = TRUE;
    8827 }
    8828 else
    8829 {
    8830 assert(term->aux.exprs != NULL);
    8831 term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
    8832 term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
    8833 }
    8834
    8835 return SCIP_OKAY;
    8836}
    8837
    8838/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
    8839static
    8841 SCIP* scip, /**< SCIP data structure */
    8842 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    8843 SCIP_CONS** conss, /**< nonlinear constraints */
    8844 int nconss /**< total number of nonlinear constraints */
    8845 )
    8846{
    8847 SCIP_CONSHDLRDATA* conshdlrdata;
    8848 SCIP_EXPRITER* it;
    8849 int c;
    8850
    8851 assert(conss != NULL || nconss == 0);
    8852
    8853 if( nconss == 0 )
    8854 return SCIP_OKAY;
    8855
    8856 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8857 assert(conshdlrdata != NULL);
    8858
    8859 /* check whether the bilinear terms have been stored already */
    8860 if( conshdlrdata->bilinterms != NULL )
    8861 return SCIP_OKAY;
    8862
    8863 /* create and initialize iterator */
    8867
    8868 /* iterate through all constraints */
    8869 for( c = 0; c < nconss; ++c )
    8870 {
    8871 SCIP_CONSDATA* consdata;
    8872 SCIP_EXPR* expr;
    8873
    8874 assert(conss != NULL && conss[c] != NULL);
    8875 consdata = SCIPconsGetData(conss[c]);
    8876 assert(consdata != NULL);
    8877
    8878 /* iterate through all expressions */
    8879 for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    8880 {
    8881 SCIP_EXPR** children = SCIPexprGetChildren(expr);
    8882 SCIP_VAR* x = NULL;
    8883 SCIP_VAR* y = NULL;
    8884
    8885 /* check whether the expression is of the form f(..)^2 */
    8886 if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
    8887 {
    8888 x = SCIPgetExprAuxVarNonlinear(children[0]);
    8889 y = x;
    8890 }
    8891 /* check whether the expression is of the form f(..) * g(..) */
    8892 else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
    8893 {
    8894 x = SCIPgetExprAuxVarNonlinear(children[0]);
    8895 y = SCIPgetExprAuxVarNonlinear(children[1]);
    8896 }
    8897
    8898 /* add variables to the hash table */
    8899 if( x != NULL && y != NULL )
    8900 {
    8903 }
    8904 }
    8905 }
    8906
    8907 /* release iterator */
    8908 SCIPfreeExpriter(&it);
    8909
    8910 return SCIP_OKAY;
    8911}
    8912
    8913/** store x, y and the locks in a new bilinear term */
    8914static
    8916 SCIP* scip, /**< SCIP data structure */
    8917 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    8918 SCIP_VAR* x, /**< the first variable */
    8919 SCIP_VAR* y, /**< the second variable */
    8920 int nlockspos, /**< number of positive locks of the bilinear term */
    8921 int nlocksneg, /**< number of negative locks of the bilinear term */
    8922 int* idx, /**< pointer to store the position of the term in bilinterms array */
    8923 SCIP_Bool existing /**< whether the term exists explicitly in the problem */
    8924 )
    8925{
    8926 SCIP_CONSHDLRDATA* conshdlrdata;
    8928
    8929 assert(conshdlr != NULL);
    8930 assert(x != NULL);
    8931 assert(y != NULL);
    8932 assert(nlockspos >= 0);
    8933 assert(nlocksneg >= 0);
    8934
    8935 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    8936 assert(conshdlrdata != NULL);
    8937
    8938 /* ensure that x.index <= y.index */
    8939 if( SCIPvarCompare(x, y) == 1 )
    8940 {
    8941 SCIPswapPointers((void**)&x, (void**)&y);
    8942 }
    8943 assert(SCIPvarCompare(x, y) < 1);
    8944
    8945 *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
    8946
    8947 /* update or create the term */
    8948 if( *idx >= 0 )
    8949 { /* the term has already been added */
    8950 assert(conshdlrdata->bilinterms[*idx].x == x);
    8951 assert(conshdlrdata->bilinterms[*idx].y == y);
    8952
    8953 /* get term and add locks */
    8954 term = &conshdlrdata->bilinterms[*idx];
    8955 assert(existing <= term->existing); /* implicit terms are added after existing ones */
    8956 term->nlockspos += nlockspos;
    8957 term->nlocksneg += nlocksneg;
    8958 }
    8959 else
    8960 { /* this is the first time we encounter this product */
    8961 /* ensure size of bilinterms array */
    8962 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
    8963
    8964 *idx = conshdlrdata->nbilinterms;
    8965
    8966 /* get term and set values in the created bilinear term */
    8967 term = &conshdlrdata->bilinterms[*idx];
    8968 assert(term != NULL);
    8969 term->x = x;
    8970 term->y = y;
    8971 term->nauxexprs = 0;
    8972 term->auxexprssize = 0;
    8973 term->nlockspos = nlockspos;
    8974 term->nlocksneg = nlocksneg;
    8975 term->existing = existing;
    8976 if( existing )
    8977 term->aux.var = NULL;
    8978 else
    8979 term->aux.exprs = NULL;
    8980
    8981 /* increase the total number of bilinear terms */
    8982 ++(conshdlrdata->nbilinterms);
    8983
    8984 /* save to the hashtable */
    8985 if( conshdlrdata->bilinhashtable == NULL )
    8986 {
    8987 SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
    8988 bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
    8989 (void*)conshdlrdata) );
    8990 }
    8991 assert(conshdlrdata->bilinhashtable != NULL);
    8992
    8993 /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
    8994 * because zero can not be inserted into hash table
    8995 */
    8996 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
    8997
    8998 /* capture product variables */
    9001 }
    9002
    9003 return SCIP_OKAY;
    9004}
    9005
    9006/** frees array of bilinear terms and hash table */
    9007static
    9009 SCIP* scip, /**< SCIP data structure */
    9010 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
    9011 )
    9012{
    9013 int i;
    9014 int j;
    9015
    9016 assert(conshdlrdata != NULL);
    9017
    9018 /* check whether bilinear terms have been stored */
    9019 if( conshdlrdata->bilinterms == NULL )
    9020 {
    9021 assert(conshdlrdata->bilinterms == NULL);
    9022 assert(conshdlrdata->nbilinterms == 0);
    9023 assert(conshdlrdata->bilintermssize == 0);
    9024
    9025 return SCIP_OKAY;
    9026 }
    9027
    9028 /* release variables */
    9029 for( i = 0; i < conshdlrdata->nbilinterms; ++i )
    9030 {
    9031 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
    9032 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
    9033
    9034 for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
    9035 {
    9036 if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
    9037 {
    9038 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
    9039 }
    9040 SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
    9041 }
    9042
    9043 if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
    9044 {
    9045 SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
    9046 continue;
    9047 }
    9048
    9049 /* the rest is for simple terms with a single auxvar */
    9050
    9051 /* it might be that there is a bilinear term without a corresponding auxiliary variable */
    9052 if( conshdlrdata->bilinterms[i].aux.var != NULL )
    9053 {
    9054 SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
    9055 }
    9056 }
    9057
    9058 /* free hash table */
    9059 if( conshdlrdata->bilinhashtable != NULL )
    9060 {
    9061 SCIPhashtableFree(&conshdlrdata->bilinhashtable);
    9062 }
    9063
    9064 /* free bilinterms array; reset counters */
    9065 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
    9066 conshdlrdata->nbilinterms = 0;
    9067 conshdlrdata->bilintermssize = 0;
    9068
    9069 return SCIP_OKAY;
    9070}
    9071
    9072/*
    9073 * vertex polyhedral separation
    9074 */
    9075
    9076/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
    9077static
    9079 SCIP* scip, /**< SCIP data structure */
    9080 int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
    9081 SCIP_LPI** lp /**< pointer to store created LP */
    9082 )
    9083{
    9084 SCIP_Real* obj;
    9085 SCIP_Real* lb;
    9086 SCIP_Real* ub;
    9087 SCIP_Real* val;
    9088 int* beg;
    9089 int* ind;
    9090 unsigned int nnonz;
    9091 unsigned int ncols;
    9092 unsigned int nrows;
    9093 unsigned int i;
    9094 unsigned int k;
    9095
    9096 assert(scip != NULL);
    9097 assert(lp != NULL);
    9098 assert(nvars > 0);
    9099 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
    9100
    9101 SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
    9102
    9103 /* create lpi to store the LP */
    9105
    9106 nrows = (unsigned int)nvars + 1;
    9107 ncols = POWEROFTWO((unsigned int)nvars);
    9108 nnonz = (ncols * (nrows + 1)) / 2;
    9109
    9110 /* allocate necessary memory; set obj, lb, and ub to zero */
    9111 SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
    9113 SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
    9114 SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
    9115 SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
    9116 SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
    9117
    9118 /* calculate nonzero entries in the LP */
    9119 for( i = 0, k = 0; i < ncols; ++i )
    9120 {
    9121 int row;
    9122 unsigned int a;
    9123
    9124 /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
    9125 ub[i] = SCIPlpiInfinity(*lp);
    9126
    9127 SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
    9128 beg[i] = (int)k;
    9129 row = 0;
    9130
    9131 /* iterate through the bit representation of i */
    9132 a = 1;
    9133 while( a <= i )
    9134 {
    9135 if( (a & i) != 0 )
    9136 {
    9137 val[k] = 1.0;
    9138 ind[k] = row;
    9139
    9140 SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
    9141
    9142 ++k;
    9143 }
    9144
    9145 a <<= 1;
    9146 ++row;
    9147 assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
    9148 assert(POWEROFTWO(row) == a);
    9149 }
    9150
    9151 /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
    9152 val[k] = 1.0;
    9153 ind[k] = (int)nrows - 1;
    9154 ++k;
    9155 SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
    9156 }
    9157 assert(k == nnonz);
    9158
    9159 /* load all data into LP interface
    9160 * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
    9161 */
    9162 assert(nrows <= ncols);
    9164 (int)ncols, obj, lb, ub, NULL,
    9165 (int)nrows, lb, lb, NULL,
    9166 (int)nnonz, beg, ind, val) );
    9167
    9168 /* for the last row, we can set the rhs to 1.0 already */
    9169 ind[0] = (int)nrows - 1;
    9170 val[0] = 1.0;
    9171 SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
    9172
    9173 /* free allocated memory */
    9180
    9181 return SCIP_OKAY;
    9182}
    9183
    9184/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
    9185 * \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
    9186 * set of vertices of the domain
    9187 */
    9188static
    9190 SCIP* scip, /**< SCIP data structure */
    9191 SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
    9192 SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
    9193 SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
    9194 int nallvars, /**< number of all variables */
    9195 int nvars, /**< number of unfixed variables */
    9196 int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
    9197 SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
    9198 SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
    9199 )
    9200{
    9201 SCIP_Real maxerror;
    9202 SCIP_Real facetval;
    9203 SCIP_Real funval;
    9204 SCIP_Real error;
    9205 unsigned int i;
    9206 unsigned int ncorners;
    9207 unsigned int prev;
    9208
    9209 assert(scip != NULL);
    9210 assert(funvals != NULL);
    9211 assert(box != NULL);
    9212 assert(nonfixedpos != NULL);
    9213 assert(facetcoefs != NULL);
    9214
    9215 ncorners = POWEROFTWO(nvars);
    9216 maxerror = 0.0;
    9217
    9218 /* check the origin (all variables at lower bound) */
    9219 facetval = facetconstant;
    9220 for( i = 0; i < (unsigned int) nallvars; ++i )
    9221 facetval += facetcoefs[i] * box[2*i];
    9222
    9223 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
    9224 funval = funvals[0];
    9225 if( overestimate )
    9226 error = funval - facetval;
    9227 else
    9228 error = facetval - funval;
    9229
    9230 /* update maximum error */
    9231 maxerror = MAX(error, maxerror);
    9232
    9233 prev = 0;
    9234 for( i = 1; i < ncorners; ++i )
    9235 {
    9236 unsigned int gray;
    9237 unsigned int diff;
    9238 unsigned int pos;
    9239 int origpos;
    9240
    9241 gray = i ^ (i >> 1);
    9242 diff = gray ^ prev;
    9243
    9244 /* compute position of unique 1 of diff */
    9245 pos = 0;
    9246 while( (diff >>= 1) != 0 )
    9247 ++pos;
    9248 assert(pos < (unsigned int)nvars);
    9249
    9250 origpos = nonfixedpos[pos];
    9251
    9252 if( gray > prev )
    9253 facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
    9254 else
    9255 facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
    9256
    9257 /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
    9258 funval = funvals[gray];
    9259 if( overestimate )
    9260 error = funval - facetval;
    9261 else
    9262 error = facetval - funval;
    9263
    9264 /* update maximum error */
    9265 maxerror = MAX(error, maxerror);
    9266
    9267 prev = gray;
    9268 }
    9269
    9270 SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
    9271
    9272 return maxerror;
    9273}
    9274
    9275/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
    9276static
    9278 SCIP* scip, /**< SCIP data structure */
    9279 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    9280 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
    9281 SCIP_Real* xstar, /**< point to be separated */
    9282 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
    9283 int nallvars, /**< half of the length of box */
    9284 int* nonfixedpos, /**< indices of nonfixed variables */
    9285 SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
    9286 int nvars, /**< number of nonfixed variables */
    9287 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
    9288 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
    9289 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
    9290 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
    9291 )
    9292{ /*lint --e{715}*/
    9293 SCIP_CONSHDLRDATA* conshdlrdata;
    9294 SCIP_LPI* lp;
    9295 SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
    9296 int* inds;
    9297 int ncols;
    9298 int nrows;
    9299 int i;
    9300 SCIP_Real facetvalue;
    9301 SCIP_Real mindomwidth;
    9302 SCIP_RETCODE lpsolveretcode;
    9303
    9304 assert(scip != NULL);
    9305 assert(conshdlr != NULL);
    9306 assert(xstar != NULL);
    9307 assert(box != NULL);
    9308 assert(nonfixedpos != NULL);
    9309 assert(funvals != NULL);
    9310 assert(nvars >= 0);
    9311 assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
    9312 assert(success != NULL);
    9313 assert(facetcoefs != NULL);
    9314 assert(facetconstant != NULL);
    9315
    9316 *success = FALSE;
    9317
    9318 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    9319 assert(conshdlrdata != NULL);
    9320
    9321 if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
    9322 {
    9323 SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
    9324 }
    9325
    9326 /* construct an LP for this size, if not having one already */
    9327 if( conshdlrdata->vp_lp[nvars] == NULL )
    9328 {
    9329 SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
    9330 }
    9331 lp = conshdlrdata->vp_lp[nvars];
    9332 assert(lp != NULL);
    9333
    9334 /* get number of cols and rows of separation lp */
    9335 SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
    9336 SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
    9337
    9338 /* number of columns should equal the number of corners = 2^nvars */
    9339 assert(ncols == (int)POWEROFTWO(nvars));
    9340
    9341 /* allocate necessary memory */
    9342 SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
    9343 SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
    9344
    9345 /*
    9346 * set up the described LP on the transformed space
    9347 */
    9348
    9349 for( i = 0; i < ncols; ++i )
    9350 inds[i] = i;
    9351
    9352 /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
    9353 mindomwidth = 2*SCIPinfinity(scip);
    9354 for( i = 0; i < nrows-1; ++i )
    9355 {
    9356 SCIP_Real solval;
    9357 SCIP_Real lb;
    9358 SCIP_Real ub;
    9359 int varpos;
    9360
    9361 assert(i < nvars);
    9362
    9363 varpos = nonfixedpos[i];
    9364 lb = box[2 * varpos];
    9365 ub = box[2 * varpos + 1];
    9366 solval = xstar[varpos];
    9367
    9368 if( ub - lb < mindomwidth )
    9369 mindomwidth = ub - lb;
    9370
    9371 /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
    9372 if( solval <= lb )
    9373 aux[i] = 0.0;
    9374 else if( solval >= ub )
    9375 aux[i] = 1.0;
    9376 else
    9377 aux[i] = (solval - lb) / (ub - lb);
    9378
    9379 /* perturb point to hopefully obtain a facet of the convex envelope */
    9380 if( conshdlrdata->vp_maxperturb > 0.0 )
    9381 {
    9382 assert(conshdlrdata->vp_randnumgen != NULL);
    9383
    9384 if( aux[i] == 1.0 )
    9385 aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
    9386 else if( aux[i] == 0.0 )
    9387 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
    9388 else
    9389 {
    9390 SCIP_Real perturbation;
    9391
    9392 perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
    9393 perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
    9394 aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
    9395 }
    9396 assert(0.0 < aux[i] && aux[i] < 1.0);
    9397 }
    9398
    9399 SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
    9400 }
    9401
    9402 /* update LP */
    9403 SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
    9404 SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
    9406
    9407 /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
    9408 if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
    9409 {
    9410 SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
    9411 }
    9412 /* set an iteration limit so we do not run forever */
    9414 /* 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 */
    9416 /* since we work with the dual of the LP, dual feastol determines validity of the facet
    9417 * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
    9418 * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
    9419 */
    9421
    9422#ifdef SCIP_DEBUG
    9424#endif
    9425
    9426 /*
    9427 * solve the LP and store the resulting facet for the transformed space
    9428 */
    9429 if( conshdlrdata->vp_dualsimplex )
    9430 {
    9431 lpsolveretcode = SCIPlpiSolveDual(lp);
    9432 }
    9433 else
    9434 {
    9435 lpsolveretcode = SCIPlpiSolvePrimal(lp);
    9436 }
    9437 if( lpsolveretcode == SCIP_LPERROR )
    9438 {
    9439 SCIPdebugMsg(scip, "LP error, aborting.\n");
    9440 goto CLEANUP;
    9441 }
    9442 SCIP_CALL( lpsolveretcode );
    9443
    9444 /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
    9445 if( !SCIPlpiIsDualFeasible(lp) )
    9446 {
    9447 SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
    9448 goto CLEANUP;
    9449 }
    9450
    9451 /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
    9452 * columns than needed, in particular, \bar \beta is the last dual multiplier
    9453 */
    9454 SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
    9455
    9456 for( i = 0; i < nvars; ++i )
    9457 facetcoefs[nonfixedpos[i]] = aux[i];
    9458 /* last dual multiplier is the constant */
    9459 *facetconstant = aux[nrows - 1];
    9460
    9461#ifdef SCIP_DEBUG
    9462 SCIPdebugMsg(scip, "facet for the transformed problem: ");
    9463 for( i = 0; i < nallvars; ++i )
    9464 {
    9465 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
    9466 }
    9467 SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
    9468#endif
    9469
    9470 /*
    9471 * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
    9472 */
    9473
    9474 SCIPdebugMsg(scip, "facet in orig. space: ");
    9475
    9476 facetvalue = 0.0;
    9477 for( i = 0; i < nvars; ++i )
    9478 {
    9479 SCIP_Real lb;
    9480 SCIP_Real ub;
    9481 int varpos;
    9482
    9483 varpos = nonfixedpos[i];
    9484 lb = box[2 * varpos];
    9485 ub = box[2 * varpos + 1];
    9486 assert(!SCIPisEQ(scip, lb, ub));
    9487
    9488 /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
    9489 facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
    9490
    9491 /* beta = beta_bar - sum_i alpha_i * lb_i */
    9492 *facetconstant -= facetcoefs[varpos] * lb;
    9493
    9494 /* evaluate */
    9495 facetvalue += facetcoefs[varpos] * xstar[varpos];
    9496
    9497 SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
    9498 }
    9499 SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
    9500
    9501 /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
    9502 facetvalue += *facetconstant;
    9503
    9504 SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
    9505
    9506 /* if overestimate, then we want facetvalue < targetvalue
    9507 * if underestimate, then we want facetvalue > targetvalue
    9508 * if none holds, give up
    9509 * so maybe here we should check against the minimal violation
    9510 */
    9511 if( overestimate == (facetvalue > targetvalue) )
    9512 {
    9513 SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
    9514 goto CLEANUP;
    9515 }
    9516
    9517 /* if we made it until here, then we have a nice facet */
    9518 *success = TRUE;
    9519
    9520CLEANUP:
    9521 /* free allocated memory */
    9522 SCIPfreeBufferArray(scip, &inds);
    9524
    9525 return SCIP_OKAY;
    9526}
    9527
    9528/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
    9529 *
    9530 * In other words, compute the line that passes through two given points.
    9531 */
    9532static
    9534 SCIP* scip, /**< SCIP data structure */
    9535 SCIP_Real left, /**< left coordinate */
    9536 SCIP_Real right, /**< right coordinate */
    9537 SCIP_Real funleft, /**< value of function in left coordinate */
    9538 SCIP_Real funright, /**< value of function in right coordinate */
    9539 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
    9540 SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
    9541 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
    9542 )
    9543{
    9544 assert(scip != NULL);
    9545 assert(SCIPisLE(scip, left, right));
    9546 assert(!SCIPisInfinity(scip, -left));
    9547 assert(!SCIPisInfinity(scip, right));
    9548 assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
    9549 assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
    9550 assert(success != NULL);
    9551 assert(facetcoef != NULL);
    9552 assert(facetconstant != NULL);
    9553
    9554 *facetcoef = (funright - funleft) / (right - left);
    9555 *facetconstant = funleft - *facetcoef * left;
    9556
    9557 *success = TRUE;
    9558
    9559 return SCIP_OKAY;
    9560}
    9561
    9562/** given three points, constructs coefficient of equation for hyperplane generated by these three points
    9563 *
    9564 * Three points a, b, and c are given.
    9565 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
    9566 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
    9567 */
    9568static
    9570 SCIP* scip, /**< SCIP data structure */
    9571 SCIP_Real a1, /**< first coordinate of a */
    9572 SCIP_Real a2, /**< second coordinate of a */
    9573 SCIP_Real a3, /**< third coordinate of a */
    9574 SCIP_Real b1, /**< first coordinate of b */
    9575 SCIP_Real b2, /**< second coordinate of b */
    9576 SCIP_Real b3, /**< third coordinate of b */
    9577 SCIP_Real c1, /**< first coordinate of c */
    9578 SCIP_Real c2, /**< second coordinate of c */
    9579 SCIP_Real c3, /**< third coordinate of c */
    9580 SCIP_Real* alpha, /**< coefficient of first coordinate */
    9581 SCIP_Real* beta, /**< coefficient of second coordinate */
    9582 SCIP_Real* gamma_, /**< coefficient of third coordinate */
    9583 SCIP_Real* delta /**< constant right-hand side */
    9584 )
    9585{
    9586 assert(scip != NULL);
    9587 assert(alpha != NULL);
    9588 assert(beta != NULL);
    9589 assert(gamma_ != NULL);
    9590 assert(delta != NULL);
    9591
    9592 *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
    9593 *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
    9594 *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
    9595 *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
    9596
    9597 /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
    9598
    9599 if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
    9600 SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
    9601 SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
    9602 {
    9603 SCIPdebugMsg(scip, "activity above SCIP infinity\n");
    9604 *delta = 0.0;
    9605 *alpha = 0.0;
    9606 *beta = 0.0;
    9607 *gamma_ = 0.0;
    9608 return SCIP_OKAY;
    9609 }
    9610
    9611 /* check if hyperplane contains all three points (necessary because of numerical troubles) */
    9612 if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
    9613 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
    9614 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
    9615 {
    9616 SCIP_Real m[9];
    9617 SCIP_Real rhs[3];
    9618 SCIP_Real x[3];
    9619 SCIP_Bool success;
    9620
    9621 /*
    9622 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));
    9623 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));
    9624 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));
    9625 */
    9626
    9627 /* initialize matrix column-wise */
    9628 m[0] = a1;
    9629 m[1] = b1;
    9630 m[2] = c1;
    9631 m[3] = a2;
    9632 m[4] = b2;
    9633 m[5] = c2;
    9634 m[6] = a3;
    9635 m[7] = b3;
    9636 m[8] = c3;
    9637
    9638 rhs[0] = 1.0;
    9639 rhs[1] = 1.0;
    9640 rhs[2] = 1.0;
    9641
    9642 SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
    9643
    9644 /* solve the linear problem */
    9645 SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
    9646
    9647 *delta = rhs[0];
    9648 *alpha = x[0];
    9649 *beta = x[1];
    9650 *gamma_ = x[2];
    9651
    9652 /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
    9653 * not add a cut to SCIP and that all assertions are trivially fulfilled
    9654 */
    9655 if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
    9656 !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
    9657 !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
    9658 {
    9659 SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
    9660 *delta = 0.0;
    9661 *alpha = 0.0;
    9662 *beta = 0.0;
    9663 *gamma_ = 0.0;
    9664 }
    9665 }
    9666
    9667 if( *gamma_ < 0.0 )
    9668 {
    9669 *alpha = -*alpha;
    9670 *beta = -*beta;
    9671 *gamma_ = -*gamma_;
    9672 *delta = -*delta;
    9673 }
    9674
    9675 return SCIP_OKAY;
    9676}
    9677
    9678/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
    9679static
    9681 SCIP* scip, /**< SCIP data structure */
    9682 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
    9683 SCIP_Real p1[2], /**< first vertex of box */
    9684 SCIP_Real p2[2], /**< second vertex of box */
    9685 SCIP_Real p3[2], /**< third vertex of box */
    9686 SCIP_Real p4[2], /**< forth vertex of box */
    9687 SCIP_Real p1val, /**< value in p1 */
    9688 SCIP_Real p2val, /**< value in p2 */
    9689 SCIP_Real p3val, /**< value in p3 */
    9690 SCIP_Real p4val, /**< value in p4 */
    9691 SCIP_Real xstar[2], /**< point to be separated */
    9692 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
    9693 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
    9694 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
    9695 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
    9696 )
    9697{
    9698 SCIP_Real alpha, beta, gamma_, delta;
    9699 SCIP_Real xstarval, candxstarval = 0.0;
    9700 int leaveout;
    9701
    9702 assert(scip != NULL);
    9703 assert(success != NULL);
    9704 assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
    9705 assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
    9706 assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
    9707 assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
    9708 assert(facetcoefs != NULL);
    9709 assert(facetconstant != NULL);
    9710
    9711 *success = FALSE;
    9712
    9713 /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
    9714 if( !overestimate )
    9715 {
    9716 p1val = -p1val;
    9717 p2val = -p2val;
    9718 p3val = -p3val;
    9719 p4val = -p4val;
    9720 targetvalue = -targetvalue;
    9721 }
    9722
    9723 SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
    9724 SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
    9725 SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
    9726 SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
    9727
    9728 /* Compute coefficients alpha, beta, gamma (>0), delta such that
    9729 * alpha*x + beta*y + gamma*z = delta
    9730 * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
    9731 * the fourth corner point lies below this hyperplane.
    9732 * 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.,
    9733 * alpha*x + beta*y - delta <= -gamma * f(x,y),
    9734 * or, equivalently,
    9735 * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
    9736 */
    9737 for( leaveout = 1; leaveout <= 4; ++leaveout )
    9738 {
    9739 switch( leaveout)
    9740 {
    9741 case 1 :
    9742 /* get hyperplane through p2, p3, p4 */
    9743 SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
    9744 &alpha, &beta, &gamma_, &delta) );
    9745 /* if not underestimating in p1, then go to next candidate */
    9746 if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
    9747 continue;
    9748 break;
    9749
    9750 case 2 :
    9751 /* get hyperplane through p1, p3, p4 */
    9752 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
    9753 &alpha, &beta, &gamma_, &delta) );
    9754 /* if not underestimating in p2, then go to next candidate */
    9755 if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
    9756 continue;
    9757 break;
    9758
    9759 case 3 :
    9760 /* get hyperplane through p1, p2, p4 */
    9761 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
    9762 &alpha, &beta, &gamma_, &delta) );
    9763 /* if not underestimating in p3, then go to next candidate */
    9764 if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
    9765 continue;
    9766 break;
    9767
    9768 case 4 :
    9769 /* get hyperplane through p1, p2, p3 */
    9770 SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
    9771 &alpha, &beta, &gamma_, &delta) );
    9772 /* if not underestimating in p4, then stop */
    9773 if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
    9774 continue;
    9775 break;
    9776
    9777 default: /* only for lint */
    9778 alpha = SCIP_INVALID;
    9779 beta = SCIP_INVALID;
    9780 gamma_ = SCIP_INVALID;
    9781 delta = SCIP_INVALID;
    9782 break;
    9783 }
    9784
    9785 /* check if bad luck: should not happen if numerics are fine */
    9786 if( SCIPisZero(scip, gamma_) )
    9787 continue;
    9788 assert(!SCIPisNegative(scip, gamma_));
    9789
    9790 /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
    9791 if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
    9792 ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
    9793 continue;
    9794
    9795 SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
    9796
    9797 /* value of hyperplane candidate in xstar */
    9798 xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
    9799
    9800 /* if reaching target and first or better than previous candidate, then update */
    9801 if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
    9802 {
    9803 /* flip hyperplane */
    9804 if( !overestimate )
    9805 gamma_ = -gamma_;
    9806
    9807 facetcoefs[0] = -alpha/gamma_;
    9808 facetcoefs[1] = -beta/gamma_;
    9809 *facetconstant = delta/gamma_;
    9810
    9811 *success = TRUE;
    9812 candxstarval = xstarval;
    9813 }
    9814 }
    9815
    9816 return SCIP_OKAY;
    9817}
    9818
    9819/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
    9820 * graph yet) in an array
    9821 */
    9822static
    9824 SCIP* scip, /**< SCIP pointer */
    9825 int** openidx, /**< address of openidx array */
    9826 int nelems, /**< number of elements that need to be stored */
    9827 int* maxnelems /**< pointer to store maximum number that can be stored */
    9828 )
    9829{
    9830 assert(scip != NULL);
    9831 assert(openidx != NULL);
    9832 assert(maxnelems != NULL);
    9833
    9834 if( nelems > *maxnelems )
    9835 {
    9836 int newsize;
    9837
    9838 newsize = SCIPcalcMemGrowSize(scip, nelems);
    9839 assert(newsize >= nelems);
    9840
    9841 SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
    9842
    9843 *maxnelems = newsize;
    9844 }
    9845
    9846 return SCIP_OKAY;
    9847}
    9848
    9849/** ensures that we can store information about local variables in an array */
    9850static
    9852 SCIP* scip, /**< SCIP pointer */
    9853 SCIP_VAR*** vars, /**< address of variable array */
    9854 SCIP_Real** vals, /**< address of value array */
    9855 int nelems, /**< number of elements that need to be stored */
    9856 int* maxnelems /**< pointer to store maximum number that can be stored */
    9857 )
    9858{
    9859 assert(scip != NULL);
    9860 assert(vars != NULL);
    9861 assert(vals != NULL);
    9862 assert(maxnelems != NULL);
    9863
    9864 if( nelems > *maxnelems )
    9865 {
    9866 int newsize;
    9867
    9868 newsize = SCIPcalcMemGrowSize(scip, nelems);
    9869 assert(newsize > *maxnelems);
    9870
    9871 SCIP_CALL( SCIPreallocBufferArray(scip, vars, newsize) );
    9872 SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
    9873
    9874 *maxnelems = newsize;
    9875 }
    9876
    9877 return SCIP_OKAY;
    9878}
    9879
    9880/** tries to add gadget for finding signed permutations of bilinear products
    9881 *
    9882 * If a product has exactly two children being variables, negating both simultanteoulsy
    9883 * is a signed permutation.
    9884 */
    9885static
    9887 SCIP* scip, /**< SCIP pointer */
    9888 SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
    9889 SCIP_CONS* cons, /**< constraint containing product expression */
    9890 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    9891 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
    9892 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
    9893 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
    9894 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    9895 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    9896 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    9897 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
    9898 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
    9899 )
    9900{
    9901 SYM_EXPRDATA* symdata;
    9902 SCIP_EXPR** children;
    9903 SCIP_VAR* var1 = NULL;
    9904 SCIP_VAR* var2 = NULL;
    9905 SCIP_Real val1 = 0.0;
    9906 SCIP_Real val2 = 0.0;
    9907 SCIP_Real coef;
    9908 SCIP_Real prodval;
    9909 SCIP_Real constant;
    9910 int nlocvars;
    9911 int optype;
    9912 int nchildren;
    9913 int prodidx;
    9914 int coefidx1;
    9915 int coefidx2;
    9916 int childidx;
    9917
    9918 assert(scip != NULL);
    9919 assert(expr != NULL);
    9920 assert(SCIPisExprProduct(scip, expr));
    9921 assert(graph != NULL);
    9922 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
    9923 assert(consvars != NULL);
    9924 assert(consvals != NULL);
    9925 assert(maxnconsvars != NULL);
    9926 assert(*maxnconsvars > 0);
    9927 assert(handledexprs != NULL);
    9928 assert(success != NULL);
    9929
    9930 *success = FALSE;
    9931
    9932 /* we require exactly two children being variables */
    9933 nchildren = SCIPexprGetNChildren(expr);
    9934 if( nchildren != 2 )
    9935 return SCIP_OKAY;
    9936
    9937 children = SCIPexprGetChildren(expr);
    9938 if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
    9939 return SCIP_OKAY;
    9940
    9941 /* check whether each child is not multi-aggregated and is not shifted */
    9942 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
    9943
    9944 for( childidx = 0; childidx < 2; ++childidx )
    9945 {
    9946 (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
    9947 (*consvals)[0] = 1.0;
    9948 nlocvars = 1;
    9949 constant = 0.0;
    9950
    9951 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
    9952 &constant, SCIPconsIsTransformed(cons)) );
    9953
    9954 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
    9955 return SCIP_OKAY;
    9956
    9957 if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
    9958 != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
    9959 return SCIP_OKAY;
    9960
    9961 /* store information about variables */
    9962 if( childidx == 0 )
    9963 {
    9964 var1 = (*consvars)[0];
    9965 val1 = (*consvals)[0];
    9966 }
    9967 else
    9968 {
    9969 var2 = (*consvars)[0];
    9970 val2 = (*consvals)[0];
    9971 }
    9972 }
    9973 assert(var1 != NULL);
    9974 assert(var2 != NULL);
    9975
    9976 /* store the we handle the children */
    9977 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
    9978 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
    9979
    9980 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
    9981 assert(symdata != NULL);
    9982 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
    9983
    9984 coef = SCIPgetSymExprdataConstants(symdata)[0];
    9985
    9986 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
    9987
    9988 /* add gadget modeling the product
    9989 *
    9990 * Since the constants are 0, each variable is centered at the origin, which leads to
    9991 * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
    9992 * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
    9993 * negate both variables simulataneously.
    9994 */
    9996 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
    9997 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
    9998
    9999 prodval = coef * val1 * val2;
    10000
    10001 /* introduce nodes for the product value and its negation; since flipping both variables
    10002 * simultaneously is a signed symmetry, assign both nodes the same value
    10003 */
    10004 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
    10005 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
    10006
    10007 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
    10008 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
    10009 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
    10010
    10011 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
    10012 SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
    10013 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
    10014 SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
    10015 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
    10016 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
    10017 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
    10018 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
    10019
    10020 *success = TRUE;
    10021
    10022 return SCIP_OKAY;
    10023}
    10024
    10025/** returns whether an operator is even and, if yes, stores data about operator */
    10026static
    10028 SCIP* scip, /**< SCIP pointer */
    10029 SCIP_EXPR* expr, /**< expression corresponding to operator */
    10030 SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
    10031 * needed for symmetry computation */
    10032 SCIP_Real* value /**< pointer to store value for symmetry computation */
    10033 )
    10034{
    10035 SYM_EXPRDATA* symdata;
    10036
    10037 assert(scip != NULL);
    10038 assert(expr != NULL);
    10039 assert(hasvalue != NULL);
    10040 assert(value != NULL);
    10041
    10042 /* check for different operators known to be even */
    10043 if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
    10044 {
    10045 /* get remaining information needed for symmetry detection */
    10046 if( SCIPisExprSignpower(scip, expr) )
    10047 {
    10048 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
    10049 assert(symdata != NULL);
    10050 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
    10051
    10052 *value = SCIPgetSymExprdataConstants(symdata)[0];
    10053 *hasvalue = !SCIPisEQ(scip, *value, 1.0);
    10054
    10056 }
    10057 else
    10058 {
    10059 assert(SCIPisExprCos(scip, expr));
    10060 *hasvalue = FALSE;
    10061 }
    10062
    10063 return TRUE;
    10064 }
    10065 else if( SCIPisExprPower(scip, expr) )
    10066 {
    10067 SCIP_Real exponent;
    10068 int safeexponent;
    10069
    10070 /* only consider expressions corresponding to an even power */
    10071 SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
    10072 assert(symdata != NULL);
    10073 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
    10074
    10075 exponent = SCIPgetSymExprdataConstants(symdata)[0];
    10077
    10078 /* check whether the exponent is an even integer */
    10079 if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
    10080 return FALSE;
    10081
    10082 /* deal with numerics */
    10083 safeexponent = (int) (exponent + 0.5);
    10084 if( safeexponent % 2 != 0 )
    10085 return FALSE;
    10086
    10087 *hasvalue = TRUE;
    10088 *value = exponent;
    10089
    10090 return TRUE;
    10091 }
    10092 else if( SCIPisExprAbs(scip, expr) )
    10093 {
    10094 *hasvalue = FALSE;
    10095
    10096 return TRUE;
    10097 }
    10098
    10099 return FALSE;
    10100}
    10101
    10102/** returns whether a variable is centered at 0 */
    10103static
    10105 SCIP* scip, /**< SCIP pointer */
    10106 SCIP_VAR* var /**< variable to be checked */
    10107 )
    10108{
    10109 assert(scip != NULL);
    10110 assert(var != NULL);
    10111
    10113 return FALSE;
    10114
    10116 return TRUE;
    10117
    10119 return TRUE;
    10120
    10121 return FALSE;
    10122}
    10123
    10124/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
    10125static
    10127 SCIP* scip, /**< SCIP pointer */
    10128 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
    10129 SCIP_EXPR* child, /**< child expression of evenopexpr */
    10130 SCIP_CONS* cons, /**< constraint containing expression */
    10131 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    10132 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
    10133 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
    10134 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
    10135 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
    10136 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
    10137 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    10138 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    10139 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    10140 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
    10141 )
    10142{
    10143 SCIP_VAR* var;
    10144 SCIP_Real constant;
    10145 SCIP_Real edgeweight;
    10146 int nlocvars;
    10147 int nodeidx;
    10148 int optype;
    10149 int thisopidx;
    10150
    10151 assert(scip != NULL);
    10152 assert(evenopexpr != NULL);
    10153 assert(child != NULL);
    10154 assert(SCIPisExprVar(scip, child));
    10155 assert(cons != NULL);
    10156 assert(graph != NULL);
    10157 assert(parentidx >= 0);
    10158 assert(consvars != NULL);
    10159 assert(consvals != NULL);
    10160 assert(maxnconsvars != NULL);
    10161 assert(success != NULL);
    10162
    10163 *success = FALSE;
    10164
    10165 /* check whether child variable is (multi-)aggregated */
    10166 var = SCIPgetVarExprVar(child);
    10167 (*consvars)[0] = var;
    10168 (*consvals)[0] = 1.0;
    10169 constant = 0.0;
    10170 nlocvars = 1;
    10171
    10172 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
    10173 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
    10174 SCIPconsIsTransformed(cons)) );
    10175
    10176 /* skip multi-aggregated variables or variables with domain not centered at 0 */
    10177 if( nlocvars != 1 || !SCIPisZero(scip, constant) )
    10178 return SCIP_OKAY;
    10179
    10180 if( !varIsCenteredAt0(scip, var) )
    10181 return SCIP_OKAY;
    10182
    10183 /* store partial information for gadget */
    10184 var = (*consvars)[0];
    10185 edgeweight = (*consvals)[0];
    10186
    10187 /* add gadget to graph for even univariate expression */
    10188 *success = TRUE;
    10189
    10191
    10192 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
    10193 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
    10194
    10195 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
    10196 TRUE, edgeweight) );
    10198 TRUE, edgeweight) );
    10199
    10200 if( hassymval )
    10201 {
    10202 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
    10203 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
    10204 }
    10205
    10206 return SCIP_OKAY;
    10207}
    10208
    10209/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
    10210static
    10212 SCIP* scip, /**< SCIP pointer */
    10213 SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
    10214 SCIP_EXPR* child, /**< child expression of evenopexpr */
    10215 SCIP_CONS* cons, /**< constraint containing expression */
    10216 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    10217 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
    10218 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
    10219 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
    10220 SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
    10221 SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
    10222 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    10223 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    10224 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    10225 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
    10226 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
    10227 )
    10228{
    10229 SCIP_VAR* var;
    10230 SCIP_Real constant;
    10231 SCIP_Real weight;
    10232 int nlocvars;
    10233 int nodeidx;
    10234 int optype;
    10235 int thisopidx;
    10236 int i;
    10237
    10238 assert(scip != NULL);
    10239 assert(evenopexpr != NULL);
    10240 assert(child != NULL);
    10241 assert(SCIPisExprSum(scip, child));
    10242 assert(cons != NULL);
    10243 assert(graph != NULL);
    10244 assert(parentidx >= 0);
    10245 assert(consvars != NULL);
    10246 assert(consvals != NULL);
    10247 assert(maxnconsvars != NULL);
    10248 assert(handledexprs != NULL);
    10249 assert(success != NULL);
    10250
    10251 *success = FALSE;
    10252
    10253 /* check whether child variable is (multi-)aggregated and whether all children are variables */
    10254 nlocvars = SCIPexprGetNChildren(child);
    10255
    10256 SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
    10257
    10258 for( i = 0; i < nlocvars; ++i)
    10259 {
    10260 if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
    10261 {
    10262 (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
    10263 (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
    10264 }
    10265 else
    10266 return SCIP_OKAY;
    10267 }
    10268 constant = SCIPgetConstantExprSum(child);
    10269
    10270 SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
    10271 SCIPconsIsTransformed(cons)) );
    10272
    10273 /* we can only handle the case without constant and two variables with domain centered at origin */
    10274 if( nlocvars > 2 || !SCIPisZero(scip, constant) )
    10275 return SCIP_OKAY;
    10276 assert(nlocvars > 0);
    10277
    10278 var = (*consvars)[0];
    10279 if( !varIsCenteredAt0(scip, var) )
    10280 return SCIP_OKAY;
    10281
    10282 if( nlocvars == 2 )
    10283 {
    10284 var = (*consvars)[1];
    10285 if( !varIsCenteredAt0(scip, var) )
    10286 return SCIP_OKAY;
    10287 }
    10288
    10289 /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
    10290 *success = TRUE;
    10291 for( i = 0; i < SCIPexprGetNChildren(child); ++i )
    10292 {
    10293 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
    10294 }
    10295
    10297
    10298 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
    10299 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
    10300
    10301 if( hassymval )
    10302 {
    10303 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
    10304 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
    10305 }
    10306
    10307 if( nlocvars == 1 )
    10308 {
    10309 var = (*consvars)[0];
    10310 weight = (*consvals)[0];
    10311
    10312 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
    10313 TRUE, weight) );
    10315 TRUE, weight) );
    10316 }
    10317 else
    10318 {
    10319 int dummyidx1;
    10320 int dummyidx2;
    10321
    10322 /* add dummy nodes for gadget */
    10323 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
    10324 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
    10325
    10326 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
    10327 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
    10328 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
    10329
    10330 /* connect dummy nodes with variables */
    10331 for( i = 0; i < 2; ++i)
    10332 {
    10333 var = (*consvars)[i];
    10334 weight = ABS((*consvals)[i]);
    10335
    10336 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, SCIPgetSymgraphVarnodeidx(scip, graph, var),
    10337 TRUE, weight) );
    10339 TRUE, weight) );
    10340 }
    10341 }
    10342
    10343 return SCIP_OKAY;
    10344}
    10345
    10346/** tries to add gadget for finding signed permutations of even univariate operators
    10347 *
    10348 * We handle two cases. First, if a univariate operator is even and has a variable
    10349 * as child, negating the child is signed permutation. Second, the univariate operator
    10350 * is even and has a weighted sum of two variables as child.
    10351 */
    10352static
    10354 SCIP* scip, /**< SCIP pointer */
    10355 SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
    10356 SCIP_CONS* cons, /**< constraint containing expression */
    10357 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    10358 int parentidx, /**< index of parent node in symmetry detection graph for gadget */
    10359 SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
    10360 SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
    10361 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    10362 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    10363 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    10364 SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
    10365 SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
    10366 )
    10367{
    10368 SCIP_EXPR* child;
    10369 SCIP_Real val = 0.0;
    10370 SCIP_Bool hasval = FALSE;
    10371
    10372 assert(scip != NULL);
    10373 assert(expr != NULL);
    10374 assert(graph != NULL);
    10375 assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
    10376 assert(consvars != NULL);
    10377 assert(consvals != NULL);
    10378 assert(maxnconsvars != NULL);
    10379 assert(*maxnconsvars > 0);
    10380 assert(handledexprs != NULL);
    10381 assert(success != NULL);
    10382
    10383 *success = FALSE;
    10384
    10385 /* ignore variable or value expressions */
    10386 if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
    10387 return SCIP_OKAY;
    10388 assert(SCIPexprGetNChildren(expr) > 0);
    10389
    10390 /* ignore operators with too many children */
    10391 if( SCIPexprGetNChildren(expr) > 1 )
    10392 return SCIP_OKAY;
    10393
    10394 /* check whether operator is even */
    10395 if( !isEvenOperator(scip, expr, &hasval, &val) )
    10396 return SCIP_OKAY;
    10397
    10398 /* we can only treat the operator if its child is a variable or a sum */
    10399 child = SCIPexprGetChildren(expr)[0];
    10400 if( SCIPisExprVar(scip, child) )
    10401 {
    10402 SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
    10403 hasval, val, consvars, consvals, maxnconsvars, success) );
    10404 }
    10405 else if( SCIPisExprSum(scip, child) )
    10406 {
    10407 SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
    10408 hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
    10409 }
    10410
    10411 if( *success )
    10412 {
    10413 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
    10414 }
    10415
    10416 return SCIP_OKAY;
    10417}
    10418
    10419/** compares two variable pointers */
    10420static
    10422{ /*lint --e{715}*/
    10423 SCIP_VAR** vars;
    10424 SCIP_VAR* var1;
    10425 SCIP_VAR* var2;
    10426
    10427 vars = (SCIP_VAR**) dataptr;
    10428
    10429 var1 = vars[ind1];
    10430 var2 = vars[ind2];
    10431 assert(var1 != NULL);
    10432 assert(var2 != NULL);
    10433
    10434 /* sort variables by their unique index */
    10435 if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
    10436 return -1;
    10437 if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
    10438 return 1;
    10439
    10440 return 0;
    10441}
    10442
    10443/** gets domain center of a variable which has not semi-infinite domain */
    10444static
    10446 SCIP* scip, /**< SCIP pointer */
    10447 SCIP_VAR* var /**< variable */
    10448 )
    10449{
    10450 SCIP_Real ub;
    10451 SCIP_Real lb;
    10452
    10453 ub = SCIPvarGetUbGlobal(var);
    10454 lb = SCIPvarGetLbGlobal(var);
    10455
    10456 assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
    10457
    10458 if ( SCIPisInfinity(scip, ub) )
    10459 return 0.0;
    10460
    10461 return (ub + lb) / 2;
    10462}
    10463
    10464/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
    10465static
    10467 SCIP* scip, /**< SCIP pointer */
    10468 SCIP_EXPR* sumexpr, /**< sum expression */
    10469 SCIP_CONS* cons, /**< constraint containing the sum expression */
    10470 SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
    10471 int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
    10472 SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
    10473 SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
    10474 int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
    10475 SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
    10476 )
    10477{
    10478 SYM_EXPRDATA* symdata;
    10479 SCIP_EXPR** children;
    10480 SCIP_EXPR** powexprs;
    10481 SCIP_EXPR** prodexprs;
    10482 SCIP_EXPR* child;
    10483 SCIP_VAR** powvars;
    10484 SCIP_VAR** prodvars;
    10485 SCIP_VAR* actvar;
    10486 SCIP_VAR* actvar2;
    10487 SCIP_VAR* var;
    10488 SCIP_VAR* var2;
    10489 SCIP_Real* sumcoefs;
    10490 SCIP_Real constant;
    10491 SCIP_Real constant2;
    10492 SCIP_Real val;
    10493 SCIP_Real val2;
    10494 SCIP_Bool* powexprused = NULL;
    10495 int* powperm = NULL;
    10496 int* prodperm = NULL;
    10497 int nchildren;
    10498 int nlocvars;
    10499 int nodeidx;
    10500 int coefnodeidx1;
    10501 int coefnodeidx2;
    10502 int cnt;
    10503 int i;
    10504 int j;
    10505 int nterms;
    10506 int npowexprs = 0;
    10507 int nprodexprs = 0;
    10508 int powcoef = 0;
    10509
    10510 assert(scip != NULL);
    10511 assert(sumexpr != NULL);
    10512 assert(cons != NULL);
    10513 assert(SCIPisExprSum(scip, sumexpr));
    10514 assert(consvars != NULL);
    10515 assert(consvals != NULL);
    10516 assert(maxnconsvars != NULL);
    10517 assert(*maxnconsvars > 0);
    10518 assert(handledexprs != NULL);
    10519
    10520 /* iterate over sum expression and extract all power and product expressions */
    10521 sumcoefs = SCIPgetCoefsExprSum(sumexpr);
    10522 children = SCIPexprGetChildren(sumexpr);
    10523 nchildren = SCIPexprGetNChildren(sumexpr);
    10524 SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
    10525 SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
    10526 SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
    10527 SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
    10528
    10529 /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
    10530 /** @todo make this work in a more general case */
    10531 for( i = 0; i < nchildren; ++i )
    10532 {
    10533 if( SCIPisExprPower(scip, children[i]) )
    10534 {
    10535 SCIP_Real exponent;
    10536
    10537 /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
    10538 if( powcoef == 0 )
    10539 {
    10540 if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
    10541 powcoef = (int) SCIPround(scip, sumcoefs[i]);
    10542 }
    10543 else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
    10544 continue;
    10545
    10546 /* we only store power expressions if their child is a variable */
    10547 assert(SCIPexprGetNChildren(children[i]) == 1);
    10548 child = SCIPexprGetChildren(children[i])[0];
    10549 if( !SCIPisExprVar(scip, child) )
    10550 continue;
    10551
    10552 /* the power is required to be a 2 */
    10553 SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
    10554 assert(symdata != NULL);
    10555 assert(SCIPgetSymExprdataNConstants(symdata) == 1);
    10556
    10557 exponent = SCIPgetSymExprdataConstants(symdata)[0];
    10558 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
    10559
    10560 if( !SCIPisEQ(scip, exponent, 2.0) )
    10561 continue;
    10562
    10563 /* we only store power expressions if the child is not multi-aggregated */
    10564 var = SCIPgetVarExprVar(child);
    10566 {
    10567 powexprs[npowexprs] = children[i];
    10568 powvars[npowexprs++] = var;
    10569 }
    10570 }
    10571 else if( SCIPisExprProduct(scip, children[i]) )
    10572 {
    10573 /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
    10574 if( powcoef == 0 )
    10575 {
    10576 if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
    10577 powcoef = (int) -SCIPround(scip, sumcoefs[i]);
    10578 }
    10579 else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
    10580 continue;
    10581
    10582 /* we only store power expressions if they have exactly two children being variables */
    10583 if( SCIPexprGetNChildren(children[i]) != 2 )
    10584 continue;
    10585 if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
    10586 || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
    10587 continue;
    10588
    10589 var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
    10590 var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
    10591
    10592 /* we only store product expressions if the children are not multi-aggregated */
    10595 {
    10596 prodexprs[nprodexprs] = children[i];
    10597 prodvars[nprodexprs++] = var;
    10598 prodexprs[nprodexprs] = children[i];
    10599 prodvars[nprodexprs++] = var2;
    10600 }
    10601 }
    10602 }
    10603
    10604 if( npowexprs == 0 || nprodexprs != npowexprs )
    10605 goto FREEMEMORY;
    10606
    10607 /* check whether the power variables and product variables match */
    10608 SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
    10609 SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
    10610
    10611 SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
    10612 SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
    10613
    10614 for( i = 0; i < npowexprs; ++i )
    10615 {
    10616 if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
    10617 goto FREEMEMORY;
    10618 }
    10619
    10620 /* if we reach this line, the variables match: we have found a potential norm constraint */
    10621 assert(npowexprs % 2 == 0);
    10622 nterms = npowexprs / 2;
    10623 SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
    10624
    10625 /* add gadget of each squared difference term */
    10626 cnt = 0;
    10627 for( i = 0; i < nterms; ++i )
    10628 {
    10629 SCIP_Bool var1found = FALSE;
    10630 SCIP_Bool var2found = FALSE;
    10631
    10632 (*consvals)[0] = 1.0;
    10633 (*consvars)[0] = prodvars[cnt++];
    10634 constant = 0.0;
    10635 nlocvars = 1;
    10636
    10638 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
    10639
    10640 if( nlocvars != 1 )
    10641 {
    10642 ++cnt;
    10643 continue;
    10644 }
    10645 actvar = (*consvars)[0];
    10646 val = (*consvals)[0];
    10647
    10648 (*consvals)[0] = 1.0;
    10649 (*consvars)[0] = prodvars[cnt++];
    10650 constant2 = 0.0;
    10651 nlocvars = 1;
    10652
    10654 &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
    10655
    10656 if( nlocvars != 1 )
    10657 continue;
    10658 actvar2 = (*consvars)[0];
    10659 val2 = (*consvals)[0];
    10660
    10661 /* we cannot handle the pair of variables if their constant/scalar differs or one variable
    10662 * cannot be centered at the origin or they are not centered around the same point
    10663 */
    10664 if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
    10668 || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
    10669 continue;
    10670
    10671 /* add gadget */
    10672 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
    10673 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
    10674 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
    10675
    10676 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
    10677 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
    10678 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
    10679 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
    10680 SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
    10681 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
    10682 SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
    10683 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
    10684 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
    10685 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
    10686 SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
    10687
    10688 /* mark product expression as handled */
    10689 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
    10690
    10691 /* find corresponding unused power expressions and mark them as handled */
    10692 for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
    10693 {
    10694 if( powexprused[j] )
    10695 continue;
    10696 assert(cnt >= 2);
    10697
    10698 if( !var1found && powvars[j] == prodvars[cnt - 2] )
    10699 {
    10700 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
    10701 powexprused[j] = TRUE;
    10702 var1found = TRUE;
    10703 }
    10704 else if( !var2found && powvars[j] == prodvars[cnt - 1] )
    10705 {
    10706 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
    10707 powexprused[j] = TRUE;
    10708 var2found = TRUE;
    10709 }
    10710 }
    10711 }
    10712
    10713 FREEMEMORY:
    10714 SCIPfreeBufferArrayNull(scip, &powexprused);
    10715 SCIPfreeBufferArrayNull(scip, &prodperm);
    10716 SCIPfreeBufferArrayNull(scip, &powperm);
    10717 SCIPfreeBufferArray(scip, &prodvars);
    10718 SCIPfreeBufferArray(scip, &powvars);
    10719 SCIPfreeBufferArray(scip, &prodexprs);
    10720 SCIPfreeBufferArray(scip, &powexprs);
    10721
    10722 return SCIP_OKAY;
    10723}
    10724
    10725/** adds symmetry information of constraint to a symmetry detection graph */
    10726static
    10728 SCIP* scip, /**< SCIP pointer */
    10729 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
    10730 SCIP_CONS* cons, /**< constraint */
    10731 SYM_GRAPH* graph, /**< symmetry detection graph */
    10732 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
    10733 )
    10734{ /*lint --e{850}*/
    10735 SCIP_EXPRITER* it;
    10736 SCIP_HASHSET* handledexprs;
    10737 SCIP_EXPR* rootexpr;
    10738 SCIP_EXPR* expr;
    10739 SCIP_VAR** consvars;
    10740 SCIP_Real* consvals;
    10741 SCIP_Real constant;
    10742 SCIP_Real parentcoef = 0.0;
    10743 int* openidx;
    10744 int maxnopenidx;
    10745 int parentidx;
    10746 int nconsvars;
    10747 int maxnconsvars;
    10748 int nlocvars;
    10749 int nopenidx = 0;
    10750 int consnodeidx;
    10751 int nodeidx;
    10752 int i;
    10753 SCIP_Bool iscolored;
    10754 SCIP_Bool hasparentcoef;
    10755
    10756 assert(scip != NULL);
    10757 assert(cons != NULL);
    10758 assert(graph != NULL);
    10759 assert(success != NULL);
    10760
    10761 /* store lhs/rhs */
    10763 SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
    10764
    10765 rootexpr = SCIPgetExprNonlinear(cons);
    10766 assert(rootexpr != NULL);
    10767
    10768 /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
    10769 expr = SCIPgetExprNonlinear(cons);
    10770 assert(expr != NULL);
    10771
    10775
    10776 /* find potential number of nodes in graph */
    10777 maxnopenidx = 0;
    10778 for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
    10779 {
    10781 continue;
    10782
    10783 ++maxnopenidx;
    10784 }
    10785
    10786 SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
    10787
    10788 maxnconsvars = SCIPgetNVars(scip);
    10789 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
    10790 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
    10791
    10792 /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
    10793 SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
    10794
    10795 /* iterate over expression tree and store nodes/edges */
    10796 expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
    10799
    10800 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    10801 {
    10802 /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
    10803 if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
    10804 {
    10805 SCIP_EXPR* baseexpr;
    10806
    10807 baseexpr = expr;
    10808 while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
    10809 expr = SCIPexpriterGetNext(it);
    10810
    10811 SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
    10812
    10813 /* leave the expression */
    10814 continue;
    10815 }
    10816
    10817 /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
    10819 {
    10820 --nopenidx;
    10821 continue;
    10822 }
    10824
    10825 /* find parentidx */
    10826 if( expr == rootexpr )
    10827 parentidx = consnodeidx;
    10828 else
    10829 {
    10830 assert(nopenidx >= 1);
    10831 parentidx = openidx[nopenidx - 1];
    10832 }
    10833
    10834 /* possibly find a coefficient assigned to the expression by the parent */
    10835 hasparentcoef = FALSE;
    10836 if ( expr != rootexpr )
    10837 {
    10838 SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
    10839 }
    10840
    10841 /* deal with different kinds of expressions and store them in the symmetry data structure */
    10842 if( SCIPisExprVar(scip, expr) )
    10843 {
    10844 /* needed to correctly reset value when leaving expression */
    10845 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
    10846
    10847 openidx[nopenidx++] = -1;
    10848
    10849 assert(maxnconsvars > 0);
    10850 assert(parentidx > 0);
    10851
    10852 /* if the parent assigns the variable a coefficient, introduce an intermediate node */
    10853 if( hasparentcoef )
    10854 {
    10855 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
    10856
    10857 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
    10858 parentidx = nodeidx;
    10859 }
    10860
    10861 /* connect (aggregation of) variable expression with its parent */
    10862 nconsvars = 1;
    10863 consvars[0] = SCIPgetVarExprVar(expr);
    10864 consvals[0] = 1.0;
    10865 constant = 0.0;
    10866
    10867 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
    10868 &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
    10869
    10870 /* check whether variable is aggregated */
    10871 if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
    10872 {
    10873 int thisidx;
    10874
    10875 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
    10876 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
    10877
    10878 parentidx = thisidx;
    10879 }
    10880 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, parentidx, consvars, consvals,
    10881 nconsvars, constant) );
    10882 }
    10883 else if( SCIPisExprValue(scip, expr) )
    10884 {
    10885 assert(parentidx > 0);
    10886
    10887 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
    10888
    10889 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
    10890
    10891 /* needed to correctly reset value when leaving expression */
    10892 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
    10893
    10894 openidx[nopenidx++] = -1;
    10895 }
    10896 else
    10897 {
    10898 SCIP_Bool usedefaultgadget = TRUE;
    10899
    10900 assert(expr == rootexpr || parentidx > 0);
    10901 assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
    10902
    10903 if( SCIPisExprSum(scip, expr) )
    10904 {
    10905 /* deal with sum expressions differently, because we can possibly aggregate linear sums */
    10906 SCIP_EXPR** children;
    10907 int sumidx;
    10908 int optype;
    10909 int childidx;
    10910
    10911 /* sums are handled by a special gadget */
    10912 usedefaultgadget = FALSE;
    10913
    10914 /* extract all children being variables and compute the sum of active variables expression */
    10915 nlocvars = 0;
    10916 children = SCIPexprGetChildren(expr);
    10917
    10918 SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
    10919
    10920 for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
    10921 {
    10922 if( !SCIPisExprVar(scip, children[childidx]) )
    10923 continue;
    10924
    10925 consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
    10926 consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
    10927
    10928 /* store that we have already handled this expression */
    10929 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
    10930 }
    10931
    10932 constant = SCIPgetConstantExprSum(expr);
    10933
    10934 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
    10935 &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
    10936
    10938
    10939 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
    10940 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
    10941
    10942 /* add the linear part of the sum */
    10943 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
    10944
    10945 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
    10946
    10947 /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
    10948 if( symtype == SYM_SYMTYPE_SIGNPERM )
    10949 {
    10950 SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
    10951 &consvars, &consvals, &maxnconsvars, handledexprs) );
    10952 }
    10953
    10954 /* store sumidx for children that have not been treated */
    10955 openidx[nopenidx++] = sumidx;
    10956 }
    10957 else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
    10958 {
    10959 SCIP_Bool succ;
    10960
    10961 SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
    10962 parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
    10963
    10964 if( succ )
    10965 {
    10966 usedefaultgadget = FALSE;
    10967 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
    10968 }
    10969 }
    10970 else if( symtype == SYM_SYMTYPE_SIGNPERM )
    10971 {
    10972 SCIP_Bool succ;
    10973
    10974 /* we can find more signed permutations for even univariate operators */
    10975 SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
    10976 &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
    10977
    10978 if( succ )
    10979 {
    10980 usedefaultgadget = FALSE;
    10981 SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
    10982 }
    10983 }
    10984
    10985 if( usedefaultgadget )
    10986 {
    10987 int opidx;
    10988 int optype;
    10989
    10991 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
    10992 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
    10993
    10994 /* possibly add constants of expression */
    10996 {
    10997 SYM_EXPRDATA* symdata;
    10998
    10999 SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
    11000 assert(symdata != NULL);
    11001
    11002 /* if expression has multiple constants, assign colors to edges to distinguish them */
    11003 iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
    11004 for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
    11005 {
    11006 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
    11007 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
    11008 }
    11009
    11010 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
    11011 }
    11012
    11013 SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
    11014
    11015 openidx[nopenidx++] = opidx;
    11016 }
    11017 }
    11018 }
    11019
    11020 SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
    11021 SCIPfreeBufferArray(scip, &consvals);
    11022 SCIPfreeBufferArray(scip, &consvars);
    11023 SCIPfreeBufferArray(scip, &openidx);
    11024 SCIPfreeExpriter(&it);
    11025
    11026 *success = TRUE;
    11027
    11028 return SCIP_OKAY;
    11029}
    11030
    11031/*
    11032 * Callback methods of constraint handler
    11033 */
    11034
    11035/** copy method for constraint handler plugins (called when SCIP copies plugins) */
    11036static
    11037SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
    11038{ /*lint --e{715}*/
    11039 SCIP_CONSHDLR* targetconshdlr;
    11040 SCIP_CONSHDLRDATA* sourceconshdlrdata;
    11041 int i;
    11042
    11043 assert(scip != NULL);
    11044 assert(conshdlr != NULL);
    11045 assert(valid != NULL);
    11046 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    11047
    11048 /* create basic data of constraint handler and include it to scip */
    11050
    11051 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    11052 assert(targetconshdlr != NULL);
    11053 assert(targetconshdlr != conshdlr);
    11054
    11055 sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
    11056 assert(sourceconshdlrdata != NULL);
    11057
    11058 /* copy nonlinear handlers */
    11059 for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
    11060 {
    11061 SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
    11062 }
    11063
    11064 *valid = TRUE;
    11065
    11066 return SCIP_OKAY;
    11067}
    11068
    11069/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
    11070static
    11071SCIP_DECL_CONSFREE(consFreeNonlinear)
    11072{ /*lint --e{715}*/
    11073 SCIP_CONSHDLRDATA* conshdlrdata;
    11074 int i;
    11075
    11076 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11077 assert(conshdlrdata != NULL);
    11078
    11079 /* free nonlinear handlers */
    11080 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11081 {
    11082 SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
    11083 assert(conshdlrdata->nlhdlrs[i] == NULL);
    11084 }
    11085 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
    11086 conshdlrdata->nlhdlrssize = 0;
    11087
    11088 /* free upgrade functions */
    11089 for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
    11090 {
    11091 assert(conshdlrdata->consupgrades[i] != NULL);
    11092 SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
    11093 }
    11094 SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
    11095
    11096 SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
    11097
    11098 SCIPqueueFree(&conshdlrdata->reversepropqueue);
    11099
    11100 if( conshdlrdata->vp_randnumgen != NULL )
    11101 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
    11102
    11103 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
    11104 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
    11105 {
    11106 if( conshdlrdata->vp_lp[i] != NULL )
    11107 {
    11108 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
    11109 }
    11110 }
    11111
    11112 assert(conshdlrdata->branchrandnumgen == NULL);
    11113
    11114 assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
    11115 SCIPhashmapFree(&conshdlrdata->var2expr);
    11116
    11117 SCIPfreeBlockMemory(scip, &conshdlrdata);
    11118 SCIPconshdlrSetData(conshdlr, NULL);
    11119
    11120 return SCIP_OKAY;
    11121}
    11122
    11123
    11124/** initialization method of constraint handler (called after problem was transformed) */
    11125static
    11126SCIP_DECL_CONSINIT(consInitNonlinear)
    11127{ /*lint --e{715}*/
    11128 SCIP_CONSHDLRDATA* conshdlrdata;
    11129 int i;
    11130
    11131 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11132 assert(conshdlrdata != NULL);
    11133
    11134 /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
    11135 conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
    11136 /* set to 1 so it is larger than initial value of lastenforound in exprs */
    11137 conshdlrdata->enforound = 1;
    11138 /* reset numbering for auxiliary variables */
    11139 conshdlrdata->auxvarid = 0;
    11140
    11141 for( i = 0; i < nconss; ++i )
    11142 {
    11143 SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
    11144 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
    11145 }
    11146
    11147 /* sort nonlinear handlers by detection priority, in decreasing order */
    11148 if( conshdlrdata->nnlhdlrs > 1 )
    11149 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
    11150
    11151 /* get heuristics for later use */
    11152 conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
    11153 conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
    11154
    11155 /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
    11156 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11157 {
    11158 SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
    11159 }
    11160
    11161 /* reset statistics in constraint handler */
    11162 conshdlrdata->nweaksepa = 0;
    11163 conshdlrdata->ntightenlp = 0;
    11164 conshdlrdata->ndesperatebranch = 0;
    11165 conshdlrdata->ndesperatecutoff = 0;
    11166 conshdlrdata->ndesperatetightenlp = 0;
    11167 conshdlrdata->nforcelp = 0;
    11168 SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
    11169 conshdlrdata->ncanonicalizecalls = 0;
    11170
    11171#ifdef ENFOLOGFILE
    11172 ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
    11173#endif
    11174
    11175 return SCIP_OKAY;
    11176}
    11177
    11178
    11179/** deinitialization method of constraint handler (called before transformed problem is freed) */
    11180static
    11181SCIP_DECL_CONSEXIT(consExitNonlinear)
    11182{ /*lint --e{715}*/
    11183 SCIP_CONSHDLRDATA* conshdlrdata;
    11184 SCIP_CONS** consssorted;
    11185 int i;
    11186
    11187 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11188 assert(conshdlrdata != NULL);
    11189
    11190 if( nconss > 0 )
    11191 {
    11192 /* for better performance of dropVarEvents, we sort by index, descending */
    11193 SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
    11194 SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
    11195
    11196 for( i = 0; i < nconss; ++i )
    11197 {
    11198 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
    11199 SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
    11200 }
    11201
    11202 SCIPfreeBufferArray(scip, &consssorted);
    11203 }
    11204
    11205 conshdlrdata->subnlpheur = NULL;
    11206 conshdlrdata->trysolheur = NULL;
    11207
    11208 if( conshdlrdata->vp_randnumgen != NULL )
    11209 SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
    11210
    11211 /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
    11212 for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
    11213 {
    11214 if( conshdlrdata->vp_lp[i] != NULL )
    11215 {
    11216 SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
    11217 }
    11218 }
    11219
    11220 if( conshdlrdata->branchrandnumgen != NULL )
    11221 SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
    11222
    11223 /* deinitialize nonlinear handlers */
    11224 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11225 {
    11226 SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
    11227 }
    11228
    11229 ENFOLOG(
    11230 if( enfologfile != NULL )
    11231 {
    11232 fclose(enfologfile);
    11233 enfologfile = NULL;
    11234 })
    11235
    11236 return SCIP_OKAY;
    11237}
    11238
    11239
    11240/** presolving initialization method of constraint handler (called when presolving is about to begin) */
    11241#ifdef SCIP_DISABLED_CODE
    11242static
    11244{ /*lint --e{715}*/
    11245 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    11246 SCIPABORT(); /*lint --e{527}*/
    11247
    11248 return SCIP_OKAY;
    11249}
    11250#else
    11251#define consInitpreNonlinear NULL
    11252#endif
    11253
    11254
    11255/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
    11256static
    11257SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
    11258{ /*lint --e{715}*/
    11259 SCIP_Bool infeasible;
    11260
    11261 if( nconss == 0 )
    11262 return SCIP_OKAY;
    11263
    11264 /* skip some extra work if already known to be infeasible */
    11266 return SCIP_OKAY;
    11267
    11268 /* simplify constraints and replace common subexpressions */
    11269 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
    11270
    11271 /* currently SCIP does not offer to communicate this,
    11272 * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
    11273 * or if a constraint expression became constant
    11274 * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
    11275 */
    11276 /* assert(!infeasible); */
    11277
    11278 /* tell SCIP that we have something nonlinear */
    11280
    11281 return SCIP_OKAY;
    11282}
    11283
    11284
    11285/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
    11286static
    11287SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
    11288{ /*lint --e{715}*/
    11289 SCIP_CONSHDLRDATA* conshdlrdata;
    11290 int i;
    11291
    11292 /* skip remaining initializations if we have solved already
    11293 * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
    11294 * assumes nonempty activities in expressions
    11295 */
    11296 switch( SCIPgetStatus(scip) )
    11297 {
    11302 return SCIP_OKAY;
    11303 default: ;
    11304 } /*lint !e788 */
    11305
    11306 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11307 assert(conshdlrdata != NULL);
    11308
    11309 /* reset one of the number of detections counter to count only current round */
    11310 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    11311 SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
    11312
    11313 SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
    11314
    11315 /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
    11316 if( conshdlrdata->branchpscostweight > 0.0 )
    11317 {
    11318 SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
    11319 if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
    11320 {
    11321 SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
    11322 SCIPABORT();
    11323 return SCIP_INVALIDDATA;
    11324 }
    11325 }
    11326
    11327 return SCIP_OKAY;
    11328}
    11329
    11330
    11331/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
    11332static
    11333SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
    11334{ /*lint --e{715}*/
    11335 SCIP_CONSHDLRDATA* conshdlrdata;
    11336
    11337 SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
    11338
    11339 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11340 assert(conshdlrdata != NULL);
    11341
    11342 /* free hash table for bilinear terms */
    11343 SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
    11344
    11345 /* reset flag to allow another call of presolSingleLockedVars() after a restart */
    11346 conshdlrdata->checkedvarlocks = FALSE;
    11347
    11348 /* drop catching new solution event, if catched before */
    11349 if( conshdlrdata->newsoleventfilterpos >= 0 )
    11350 {
    11351 SCIP_EVENTHDLR* eventhdlr;
    11352
    11353 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
    11354 assert(eventhdlr != NULL);
    11355
    11356 SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
    11357 conshdlrdata->newsoleventfilterpos = -1;
    11358 }
    11359
    11360 return SCIP_OKAY;
    11361}
    11362
    11363
    11364/** frees specific constraint data */
    11365static
    11366SCIP_DECL_CONSDELETE(consDeleteNonlinear)
    11367{ /*lint --e{715}*/
    11368 assert(consdata != NULL);
    11369 assert(*consdata != NULL);
    11370 assert((*consdata)->expr != NULL);
    11371
    11372 /* constraint locks should have been removed */
    11373 assert((*consdata)->nlockspos == 0);
    11374 assert((*consdata)->nlocksneg == 0);
    11375
    11376 /* free variable expressions */
    11377 SCIP_CALL( freeVarExprs(scip, *consdata) );
    11378
    11379 SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
    11380
    11381 /* free nonlinear row representation */
    11382 if( (*consdata)->nlrow != NULL )
    11383 {
    11384 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
    11385 }
    11386
    11387 SCIPfreeBlockMemory(scip, consdata);
    11388
    11389 return SCIP_OKAY;
    11390}
    11391
    11392
    11393/** transforms constraint data into data belonging to the transformed problem */
    11394static
    11395SCIP_DECL_CONSTRANS(consTransNonlinear)
    11396{ /*lint --e{715}*/
    11397 SCIP_EXPR* targetexpr;
    11398 SCIP_CONSDATA* sourcedata;
    11399
    11400 sourcedata = SCIPconsGetData(sourcecons);
    11401 assert(sourcedata != NULL);
    11402
    11403 /* get a copy of sourceexpr with transformed vars */
    11404 SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    11405 assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
    11406
    11407 /* create transformed cons (only captures targetexpr, no need to copy again) */
    11408 SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
    11409 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
    11410 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
    11411 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
    11412 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
    11413 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
    11414
    11415 /* release target expr */
    11416 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
    11417
    11418 return SCIP_OKAY;
    11419}
    11420
    11421
    11422/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
    11423static
    11424SCIP_DECL_CONSINITLP(consInitlpNonlinear)
    11425{ /*lint --e{715}*/
    11426 SCIP_CONSHDLRDATA* conshdlrdata;
    11427
    11428 /* create auxiliary variables and call separation initialization callbacks of the expression handlers
    11429 * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
    11430 * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
    11431 * for now, there is an assert in detectNlhdlrs to require initial if separated
    11432 */
    11433 SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
    11434
    11435 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11436 assert(conshdlrdata != NULL);
    11437
    11438 /* catch new solution event */
    11439 if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
    11440 {
    11441 SCIP_EVENTHDLR* eventhdlr;
    11442
    11443 eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
    11444 assert(eventhdlr != NULL);
    11445
    11446 SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
    11447 eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
    11448 }
    11449
    11450 /* collect all bilinear terms for which an auxvar is present
    11451 * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
    11452 * addition (and removal?) of constraints during solve
    11453 * this is typically the majority of constraints, but the method should be made more flexible
    11454 */
    11455 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
    11456
    11457 return SCIP_OKAY;
    11458}
    11459
    11460
    11461/** separation method of constraint handler for LP solutions */
    11462static
    11463SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
    11464{ /*lint --e{715}*/
    11465 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
    11466
    11467 return SCIP_OKAY;
    11468}
    11469
    11470
    11471/** separation method of constraint handler for arbitrary primal solutions */
    11472static
    11473SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
    11474{ /*lint --e{715}*/
    11475 SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
    11476
    11477 return SCIP_OKAY;
    11478}
    11479
    11480
    11481/** constraint enforcing method of constraint handler for LP solutions */
    11482static
    11483SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
    11484{ /*lint --e{715}*/
    11485 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
    11486
    11487 return SCIP_OKAY;
    11488}
    11489
    11490
    11491/** constraint enforcing method of constraint handler for relaxation solutions */
    11492static
    11493SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
    11494{ /*lint --e{715}*/
    11495 SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
    11496
    11497 return SCIP_OKAY;
    11498}
    11499
    11500
    11501/** constraint enforcing method of constraint handler for pseudo solutions */
    11502static
    11503SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
    11504{ /*lint --e{715}*/
    11505 SCIP_RESULT propresult;
    11506 SCIP_Longint soltag;
    11507 int nchgbds;
    11508 int nnotify;
    11509 int c;
    11510
    11511 soltag = SCIPgetExprNewSoltag(scip);
    11512
    11513 *result = SCIP_FEASIBLE;
    11514 for( c = 0; c < nconss; ++c )
    11515 {
    11516 SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
    11517
    11518 if( isConsViolated(scip, conss[c]) )
    11519 *result = SCIP_INFEASIBLE;
    11520 }
    11521
    11522 if( *result == SCIP_FEASIBLE )
    11523 return SCIP_OKAY;
    11524
    11525 /* try to propagate
    11526 * TODO obey propinenfo parameter, but we need something to recognize cutoff
    11527 */
    11528 nchgbds = 0;
    11529 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
    11530
    11531 if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
    11532 {
    11533 *result = propresult;
    11534 return SCIP_OKAY;
    11535 }
    11536
    11537 /* register all unfixed variables in all violated constraints as branching candidates */
    11538 SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
    11539 if( nnotify > 0 )
    11540 {
    11541 SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
    11542
    11543 return SCIP_OKAY;
    11544 }
    11545
    11546 SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
    11547 *result = SCIP_SOLVELP;
    11548 ++SCIPconshdlrGetData(conshdlr)->nforcelp;
    11549
    11550 return SCIP_OKAY;
    11551}
    11552
    11553
    11554/** feasibility check method of constraint handler for integral solutions */
    11555static
    11556SCIP_DECL_CONSCHECK(consCheckNonlinear)
    11557{ /*lint --e{715}*/
    11558 SCIP_CONSHDLRDATA* conshdlrdata;
    11559 SCIP_CONSDATA* consdata;
    11560 SCIP_Real maxviol;
    11561 SCIP_Bool maypropfeasible;
    11562 SCIP_Longint soltag;
    11563 int c;
    11564
    11565 assert(scip != NULL);
    11566 assert(conshdlr != NULL);
    11567 assert(conss != NULL || nconss == 0);
    11568 assert(result != NULL);
    11569
    11570 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11571 assert(conshdlrdata != NULL);
    11572
    11573 *result = SCIP_FEASIBLE;
    11574 soltag = SCIPgetExprNewSoltag(scip);
    11575 maxviol = 0.0;
    11576 maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
    11578
    11579 if( maypropfeasible && (sol == NULL || SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_LPSOL) && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
    11580 maypropfeasible = FALSE;
    11581
    11582 /* check nonlinear constraints for feasibility */
    11583 for( c = 0; c < nconss; ++c )
    11584 {
    11585 assert(conss != NULL && conss[c] != NULL);
    11586 SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
    11587
    11588 if( isConsViolated(scip, conss[c]) )
    11589 {
    11590 *result = SCIP_INFEASIBLE;
    11591 maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
    11592
    11593 consdata = SCIPconsGetData(conss[c]);
    11594 assert(consdata != NULL);
    11595
    11596 /* print reason for infeasibility */
    11597 if( printreason )
    11598 {
    11599 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
    11600 SCIPinfoMessage(scip, NULL, ";\n");
    11601
    11602 if( consdata->lhsviol > SCIPfeastol(scip) )
    11603 {
    11604 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
    11605 }
    11606 if( consdata->rhsviol > SCIPfeastol(scip) )
    11607 {
    11608 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
    11609 }
    11610 }
    11611 else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
    11612 {
    11613 /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
    11614 return SCIP_OKAY;
    11615 }
    11616
    11617 /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
    11618 if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
    11619 maypropfeasible = FALSE;
    11620
    11621 if( maypropfeasible )
    11622 {
    11623 if( consdata->lhsviol > SCIPfeastol(scip) )
    11624 {
    11625 /* check if there is a variable which may help to get the left hand side satisfied
    11626 * if there is no such variable, then we cannot get feasible
    11627 */
    11628 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
    11629 !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
    11630 maypropfeasible = FALSE;
    11631 }
    11632 else
    11633 {
    11634 assert(consdata->rhsviol > SCIPfeastol(scip));
    11635 /* check if there is a variable which may help to get the right hand side satisfied
    11636 * if there is no such variable, then we cannot get feasible
    11637 */
    11638 if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
    11639 !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
    11640 maypropfeasible = FALSE;
    11641 }
    11642 }
    11643 }
    11644 }
    11645
    11646 if( *result == SCIP_INFEASIBLE && maypropfeasible )
    11647 {
    11648 SCIP_Bool success;
    11649
    11650 SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
    11651
    11652 /* do not pass solution to NLP heuristic if we made it feasible this way */
    11653 if( success )
    11654 return SCIP_OKAY;
    11655 }
    11656
    11657 if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
    11658 {
    11659 SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
    11660 }
    11661
    11662 return SCIP_OKAY;
    11663}
    11664
    11665
    11666/** domain propagation method of constraint handler */
    11667static
    11668SCIP_DECL_CONSPROP(consPropNonlinear)
    11669{ /*lint --e{715}*/
    11670 int nchgbds = 0;
    11671
    11672 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
    11673 assert(nchgbds >= 0);
    11674
    11675 /* TODO would it make sense to check for redundant constraints? */
    11676
    11677 return SCIP_OKAY;
    11678}
    11679
    11680
    11681/** presolving method of constraint handler */
    11682static
    11683SCIP_DECL_CONSPRESOL(consPresolNonlinear)
    11684{ /*lint --e{715}*/
    11685 SCIP_CONSHDLRDATA* conshdlrdata;
    11686 SCIP_Bool infeasible;
    11687 int c;
    11688
    11689 *result = SCIP_DIDNOTFIND;
    11690
    11691 if( nconss == 0 )
    11692 {
    11693 *result = SCIP_DIDNOTRUN;
    11694 return SCIP_OKAY;
    11695 }
    11696
    11697 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11698 assert(conshdlrdata != NULL);
    11699
    11700 /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
    11701 SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
    11702 if( infeasible )
    11703 {
    11704 *result = SCIP_CUTOFF;
    11705 return SCIP_OKAY;
    11706 }
    11707
    11708 /* merge constraints with the same root expression */
    11709 if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
    11710 {
    11711 SCIP_Bool success;
    11712
    11713 SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
    11714 if( success )
    11715 *result = SCIP_SUCCESS;
    11716 }
    11717
    11718 /* propagate constraints */
    11719 SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
    11720 if( *result == SCIP_CUTOFF )
    11721 return SCIP_OKAY;
    11722
    11723 /* propagate function domains (TODO integrate with simplify?) */
    11724 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
    11725 {
    11726 SCIP_RESULT localresult;
    11727 SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
    11728 if( localresult == SCIP_CUTOFF )
    11729 {
    11730 *result = SCIP_CUTOFF;
    11731 return SCIP_OKAY;
    11732 }
    11733 if( localresult == SCIP_REDUCEDDOM )
    11734 *result = SCIP_REDUCEDDOM;
    11735 }
    11736
    11737 /* check for redundant constraints, remove constraints that are a value expression */
    11738 SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
    11739 if( infeasible )
    11740 {
    11741 *result = SCIP_CUTOFF;
    11742 return SCIP_OKAY;
    11743 }
    11744
    11745 /* try to upgrade constraints */
    11746 for( c = 0; c < nconss; ++c )
    11747 {
    11748 SCIP_Bool upgraded;
    11749
    11750 /* skip inactive and deleted constraints */
    11751 if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
    11752 continue;
    11753
    11754 SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
    11755 }
    11756
    11757 /* try to change continuous variables that appear linearly to be implicit integer */
    11758 if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
    11759 {
    11760 SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
    11761
    11762 if( infeasible )
    11763 {
    11764 SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
    11765 *result = SCIP_CUTOFF;
    11766 return SCIP_OKAY;
    11767 }
    11768 }
    11769
    11770 /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
    11772 && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
    11773 {
    11774 /* run this presolving technique only once because we don't want to generate identical bound disjunction
    11775 * constraints multiple times
    11776 */
    11777 conshdlrdata->checkedvarlocks = TRUE;
    11778
    11779 for( c = 0; c < nconss; ++c )
    11780 {
    11781 int tmpnchgvartypes = 0;
    11782 int tmpnaddconss = 0;
    11783
    11784 SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
    11785 SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
    11786 SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
    11787
    11788 if( infeasible )
    11789 {
    11790 SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
    11791 *result = SCIP_CUTOFF;
    11792 return SCIP_OKAY;
    11793 }
    11794
    11795 (*nchgvartypes) += tmpnchgvartypes;
    11796 (*naddconss) += tmpnaddconss;
    11797 }
    11798 }
    11799
    11800 if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
    11801 *result = SCIP_SUCCESS;
    11802 else
    11803 *result = SCIP_DIDNOTFIND;
    11804
    11805 return SCIP_OKAY;
    11806}
    11807
    11808
    11809/** propagation conflict resolving method of constraint handler */
    11810#ifdef SCIP_DISABLED_CODE
    11811static
    11813{ /*lint --e{715}*/
    11814 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    11815 SCIPABORT(); /*lint --e{527}*/
    11816
    11817 return SCIP_OKAY;
    11818}
    11819#else
    11820#define consRespropNonlinear NULL
    11821#endif
    11822
    11823
    11824/** variable rounding lock method of constraint handler */
    11825static
    11826SCIP_DECL_CONSLOCK(consLockNonlinear)
    11827{ /*lint --e{715}*/
    11828 SCIP_CONSDATA* consdata;
    11829 SCIP_EXPR_OWNERDATA* ownerdata;
    11830 SCIP_Bool reinitsolve = FALSE;
    11831
    11832 assert(conshdlr != NULL);
    11833 assert(cons != NULL);
    11834
    11835 consdata = SCIPconsGetData(cons);
    11836 assert(consdata != NULL);
    11837 assert(consdata->expr != NULL);
    11838
    11839 ownerdata = SCIPexprGetOwnerData(consdata->expr);
    11840
    11841 /* check whether we need to initSolve again because
    11842 * - we have enfo initialized (nenfos >= 0)
    11843 * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
    11844 */
    11845 if( ownerdata->nenfos >= 0 )
    11846 {
    11847 if( (consdata->nlockspos == 0) != (nlockspos == 0) )
    11848 reinitsolve = TRUE;
    11849 if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
    11850 reinitsolve = TRUE;
    11851 }
    11852
    11853 if( reinitsolve )
    11854 {
    11855 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
    11856 }
    11857
    11858 /* add locks */
    11859 SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
    11860
    11861 if( reinitsolve )
    11862 {
    11863 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
    11864 }
    11865
    11866 return SCIP_OKAY;
    11867}
    11868
    11869
    11870/** constraint activation notification method of constraint handler */
    11871static
    11872SCIP_DECL_CONSACTIVE(consActiveNonlinear)
    11873{ /*lint --e{715}*/
    11874 SCIP_CONSDATA* consdata;
    11875 SCIP_Bool infeasible = FALSE;
    11876
    11877 consdata = SCIPconsGetData(cons);
    11878 assert(consdata != NULL);
    11879
    11880 /* simplify root expression if the constraint has been added after presolving */
    11882 {
    11883 SCIP_Bool replacedroot;
    11884
    11885 if( !consdata->issimplified )
    11886 {
    11887 SCIP_EXPR* simplified;
    11888 SCIP_Bool changed;
    11889
    11890 /* simplify constraint */
    11891 SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
    11892 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    11893 assert(simplified != NULL);
    11894 consdata->expr = simplified;
    11895 consdata->issimplified = TRUE;
    11896 }
    11897
    11898 /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
    11899 SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
    11900 assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
    11901
    11902 /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
    11903 {
    11904 SCIP_CONSHDLRDATA* conshdlrdata;
    11905 SCIP_EXPRITER* it;
    11906 SCIP_EXPR* expr;
    11907
    11908 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11909 assert(conshdlrdata != NULL);
    11910
    11912 SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
    11914 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    11915 {
    11916 SCIP_EXPR* child;
    11917 SCIP_EXPR* hashmapexpr;
    11918
    11919 child = SCIPexpriterGetChildExprDFS(it);
    11920 if( !SCIPisExprVar(scip, child) )
    11921 continue;
    11922
    11923 /* check which expression is stored in the hashmap for the var of child */
    11924 hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
    11925 /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
    11926 if( hashmapexpr != NULL && hashmapexpr != child )
    11927 {
    11929 }
    11930 }
    11931 SCIPfreeExpriter(&it);
    11932 }
    11933 }
    11934
    11935 /* store variable expressions */
    11937 {
    11938 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    11939 }
    11940
    11941 /* add manually locks to constraints that are not checked for feasibility */
    11942 if( !SCIPconsIsChecked(cons) )
    11943 {
    11944 assert(consdata->nlockspos == 0);
    11945 assert(consdata->nlocksneg == 0);
    11946
    11947 SCIP_CALL( addLocks(scip, cons, 1, 0) );
    11948 }
    11949
    11950 if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
    11951 {
    11952 SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
    11953 }
    11954
    11955 /* TODO deal with infeasibility */
    11956 assert(!infeasible);
    11957
    11958 return SCIP_OKAY;
    11959}
    11960
    11961
    11962/** constraint deactivation notification method of constraint handler */
    11963static
    11964SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
    11965{ /*lint --e{715}*/
    11966 SCIP_CONSHDLRDATA* conshdlrdata;
    11967
    11968 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    11969 assert(conshdlrdata != NULL);
    11970
    11972 {
    11973 SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
    11974 }
    11975
    11977 {
    11978 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
    11980 }
    11981
    11982 /* remove locks that have been added in consActiveExpr() */
    11983 if( !SCIPconsIsChecked(cons) )
    11984 {
    11985 SCIP_CALL( addLocks(scip, cons, -1, 0) );
    11986
    11987 assert(SCIPconsGetData(cons)->nlockspos == 0);
    11988 assert(SCIPconsGetData(cons)->nlocksneg == 0);
    11989 }
    11990
    11991 return SCIP_OKAY;
    11992}
    11993
    11994
    11995/** constraint enabling notification method of constraint handler */
    11996static
    11997SCIP_DECL_CONSENABLE(consEnableNonlinear)
    11998{ /*lint --e{715}*/
    11999 SCIP_CONSHDLRDATA* conshdlrdata;
    12000
    12001 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12002 assert(conshdlrdata != NULL);
    12003
    12005 {
    12006 SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
    12007 }
    12008
    12009 return SCIP_OKAY;
    12010}
    12011
    12012
    12013/** constraint disabling notification method of constraint handler */
    12014static
    12015SCIP_DECL_CONSDISABLE(consDisableNonlinear)
    12016{ /*lint --e{715}*/
    12017 SCIP_CONSHDLRDATA* conshdlrdata;
    12018
    12019 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12020 assert(conshdlrdata != NULL);
    12021
    12023 {
    12024 SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
    12025 }
    12026
    12027 return SCIP_OKAY;
    12028}
    12029
    12030/** variable deletion of constraint handler */
    12031#ifdef SCIP_DISABLED_CODE
    12032static
    12034{ /*lint --e{715}*/
    12035 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    12036 SCIPABORT(); /*lint --e{527}*/
    12037
    12038 return SCIP_OKAY;
    12039}
    12040#else
    12041#define consDelvarsNonlinear NULL
    12042#endif
    12043
    12044
    12045/** constraint display method of constraint handler */
    12046static
    12047SCIP_DECL_CONSPRINT(consPrintNonlinear)
    12048{ /*lint --e{715}*/
    12049 SCIP_CONSDATA* consdata;
    12050
    12051 consdata = SCIPconsGetData(cons);
    12052 assert(consdata != NULL);
    12053 assert(consdata->expr != NULL);
    12054
    12055 /* print left hand side for ranged constraints */
    12056 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
    12057 {
    12058 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
    12059 }
    12060
    12061 /* print expression */
    12062 SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
    12063
    12064 /* print right hand side */
    12065 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
    12066 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
    12067 else if( !SCIPisInfinity(scip, consdata->rhs) )
    12068 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
    12069 else if( !SCIPisInfinity(scip, -consdata->lhs) )
    12070 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
    12071 else
    12072 SCIPinfoMessage(scip, file, " [free]");
    12073
    12074 return SCIP_OKAY;
    12075}
    12076
    12077
    12078/** constraint copying method of constraint handler */
    12079static
    12080SCIP_DECL_CONSCOPY(consCopyNonlinear)
    12081{ /*lint --e{715}*/
    12082 SCIP_CONSHDLR* targetconshdlr;
    12083 SCIP_EXPR* targetexpr = NULL;
    12084 SCIP_CONSDATA* sourcedata;
    12085
    12086 assert(cons != NULL);
    12087
    12088 sourcedata = SCIPconsGetData(sourcecons);
    12089 assert(sourcedata != NULL);
    12090
    12091 targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12092 assert(targetconshdlr != NULL);
    12093
    12094 SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
    12095
    12096 if( targetexpr == NULL )
    12097 *valid = FALSE;
    12098
    12099 *cons = NULL;
    12100 if( *valid )
    12101 {
    12102 /* create copy (only capture targetexpr, no need to copy again) */
    12103 SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
    12104 targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
    12105 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12106 }
    12107
    12108 if( targetexpr != NULL )
    12109 {
    12110 /* release target expr */
    12111 SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
    12112 }
    12113
    12114 return SCIP_OKAY;
    12115}
    12116
    12117
    12118/** constraint parsing method of constraint handler */
    12119static
    12120SCIP_DECL_CONSPARSE(consParseNonlinear)
    12121{ /*lint --e{715}*/
    12122 SCIP_Real lhs;
    12123 SCIP_Real rhs;
    12124 char* endptr;
    12125 SCIP_EXPR* consexprtree;
    12126
    12127 SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
    12128
    12129 assert(scip != NULL);
    12130 assert(success != NULL);
    12131 assert(str != NULL);
    12132 assert(name != NULL);
    12133 assert(cons != NULL);
    12134
    12135 *success = FALSE;
    12136
    12137 /* return if string empty */
    12138 if( !*str )
    12139 return SCIP_OKAY;
    12140
    12141 endptr = (char*)str;
    12142
    12143 /* set left and right hand side to their default values */
    12144 lhs = -SCIPinfinity(scip);
    12145 rhs = SCIPinfinity(scip);
    12146
    12147 /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
    12148
    12149 /* check for left hand side */
    12150 if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
    12151 {
    12152 /* there is a number coming, maybe it is a left-hand-side */
    12153 if( !SCIPparseReal(scip, str, &lhs, &endptr) )
    12154 {
    12155 SCIPerrorMessage("error parsing number from <%s>\n", str);
    12156 return SCIP_READERROR;
    12157 }
    12158
    12159 /* ignore whitespace */
    12160 SCIP_CALL( SCIPskipSpace(&endptr) );
    12161
    12162 if( endptr[0] != '<' || endptr[1] != '=' )
    12163 {
    12164 /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
    12165 lhs = -SCIPinfinity(scip);
    12166 }
    12167 else
    12168 {
    12169 /* it was indeed a left-hand-side, so continue parsing after it */
    12170 str = endptr + 2;
    12171
    12172 /* ignore whitespace */
    12173 SCIP_CALL( SCIPskipSpace((char**)&str) );
    12174 }
    12175 }
    12176
    12177 SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
    12178
    12179 /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
    12180 SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
    12181
    12182 /* check for left or right hand side */
    12183 SCIP_CALL( SCIPskipSpace((char**)&str) );
    12184
    12185 /* check for free constraint */
    12186 if( strncmp(str, "[free]", 6) == 0 )
    12187 {
    12188 if( !SCIPisInfinity(scip, -lhs) )
    12189 {
    12190 SCIPerrorMessage("cannot have left hand side and [free] status \n");
    12191 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12192 return SCIP_OKAY;
    12193 }
    12194 *success = TRUE;
    12195 }
    12196 else
    12197 {
    12198 switch( *str )
    12199 {
    12200 case '<':
    12201 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
    12202 break;
    12203 case '=':
    12204 if( !SCIPisInfinity(scip, -lhs) )
    12205 {
    12206 SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
    12207 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12208 return SCIP_OKAY;
    12209 }
    12210 else
    12211 {
    12212 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
    12213 lhs = rhs;
    12214 }
    12215 break;
    12216 case '>':
    12217 if( !SCIPisInfinity(scip, -lhs) )
    12218 {
    12219 SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
    12220 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12221 return SCIP_OKAY;
    12222 }
    12223 else
    12224 {
    12225 *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
    12226 break;
    12227 }
    12228 case '\0':
    12229 *success = TRUE;
    12230 break;
    12231 default:
    12232 SCIPerrorMessage("unexpected character %c\n", *str);
    12233 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12234 return SCIP_OKAY;
    12235 }
    12236 }
    12237
    12238 /* create constraint */
    12239 SCIP_CALL( createCons(scip, conshdlr, cons, name,
    12240 consexprtree, lhs, rhs, FALSE,
    12241 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12242 assert(*cons != NULL);
    12243
    12244 SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
    12245
    12246 SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
    12247
    12248 return SCIP_OKAY;
    12249}
    12250
    12251
    12252/** constraint method of constraint handler which returns the variables (if possible) */
    12253static
    12254SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
    12255{ /*lint --e{715}*/
    12256 SCIP_CONSDATA* consdata;
    12257 int i;
    12258
    12259 consdata = SCIPconsGetData(cons);
    12260 assert(consdata != NULL);
    12261
    12262 /* store variable expressions if not done so far */
    12263 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    12264
    12265 /* check whether array is too small in order to store all variables */
    12266 if( varssize < consdata->nvarexprs )
    12267 {
    12268 *success = FALSE;
    12269 return SCIP_OKAY;
    12270 }
    12271
    12272 for( i = 0; i < consdata->nvarexprs; ++i )
    12273 {
    12274 vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
    12275 assert(vars[i] != NULL);
    12276 }
    12277
    12278 *success = TRUE;
    12279
    12280 return SCIP_OKAY;
    12281}
    12282
    12283/** constraint method of constraint handler which returns the number of variables (if possible) */
    12284static
    12285SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
    12286{ /*lint --e{715}*/
    12287 SCIP_CONSDATA* consdata;
    12288
    12289 consdata = SCIPconsGetData(cons);
    12290 assert(consdata != NULL);
    12291
    12292 /* store variable expressions if not done so far */
    12293 SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
    12294
    12295 *nvars = consdata->nvarexprs;
    12296 *success = TRUE;
    12297
    12298 return SCIP_OKAY;
    12299}
    12300
    12301/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
    12302#ifdef SCIP_DISABLED_CODE
    12303static
    12305{ /*lint --e{715}*/
    12306 SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
    12307 SCIPABORT(); /*lint --e{527}*/
    12308
    12309 return SCIP_OKAY;
    12310}
    12311#else
    12312#define consGetDiveBdChgsNonlinear NULL
    12313#endif
    12314
    12315/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
    12316static
    12317SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
    12318{ /*lint --e{715}*/
    12319 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
    12320
    12321 return SCIP_OKAY;
    12322}
    12323
    12324/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
    12325static
    12326SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
    12327{ /*lint --e{715}*/
    12328 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
    12329
    12330 return SCIP_OKAY;
    12331}
    12332
    12333/** output method of cons_nonlinear statistics table to output file stream 'file' */
    12334static
    12335SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
    12336{ /*lint --e{715}*/
    12337 SCIP_CONSHDLR* conshdlr;
    12338 SCIP_CONSHDLRDATA* conshdlrdata;
    12339
    12340 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12341 assert(conshdlr != NULL);
    12342
    12343 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12344 assert(conshdlrdata != NULL);
    12345
    12346 /* print statistics for constraint handler */
    12347 SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
    12348 SCIPinfoMessage(scip, file, " enforce%-10s:", "");
    12349 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
    12350 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
    12351 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
    12352 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
    12353 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
    12354 SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
    12355 SCIPinfoMessage(scip, file, "\n");
    12356 SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
    12357 SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
    12358 SCIPinfoMessage(scip, file, "\n");
    12359
    12360 return SCIP_OKAY;
    12361}
    12362
    12363/** collect method of cons_nonlinear statistics table to SCIP_DATATREE */
    12364static
    12365SCIP_DECL_TABLECOLLECT(tableCollectNonlinear)
    12366{
    12367 SCIP_CONSHDLR* conshdlr;
    12368 SCIP_CONSHDLRDATA* conshdlrdata;
    12369
    12370 assert(scip != NULL);
    12371 assert(table != NULL);
    12372 assert(datatree != NULL);
    12373
    12374 /* Find the constraint handler */
    12375 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12376 assert(conshdlr != NULL);
    12377
    12378 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12379 assert(conshdlrdata != NULL);
    12380
    12381 /* Insert statistics */
    12382 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nweakseparation", conshdlrdata->nweaksepa) );
    12383 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ntightenlp", conshdlrdata->ntightenlp) );
    12384 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatetightenlp", conshdlrdata->ndesperatetightenlp) );
    12385 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatebranch", conshdlrdata->ndesperatebranch) );
    12386 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "ndesperatecutoff", conshdlrdata->ndesperatecutoff) );
    12387 SCIP_CALL( SCIPinsertDatatreeLong(scip, datatree, "nforcelp", conshdlrdata->nforcelp) );
    12388 SCIP_CALL( SCIPinsertDatatreeReal(scip, datatree, "canonicalizationtime", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime)) );
    12389
    12390 return SCIP_OKAY;
    12391}
    12392
    12393/** output method of nlhdlr statistics table to output file stream 'file' */
    12394static
    12395SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
    12396{ /*lint --e{715}*/
    12397 SCIP_CONSHDLR* conshdlr;
    12398 SCIP_CONSHDLRDATA* conshdlrdata;
    12399
    12400 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12401 assert(conshdlr != NULL);
    12402
    12403 /* skip nlhdlr table if there never were active nonlinear constraints */
    12404 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
    12405 return SCIP_OKAY;
    12406
    12407 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12408 assert(conshdlrdata != NULL);
    12409
    12410 /* print statistics for nonlinear handlers */
    12411 SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
    12412
    12413 return SCIP_OKAY;
    12414}
    12415
    12416/** collect method of nlhdlr statistics table to SCIP_DATATREE */
    12417static
    12418SCIP_DECL_TABLECOLLECT(tableCollectNlhdlr)
    12419{ /*lint --e{715}*/
    12420 SCIP_CONSHDLR* conshdlr;
    12421 SCIP_CONSHDLRDATA* conshdlrdata;
    12422
    12423 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12424 assert(conshdlr != NULL);
    12425
    12426 /* skip nlhdlr table if there never were active nonlinear constraints */
    12427 if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
    12428 return SCIP_OKAY;
    12429
    12430 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12431 assert(conshdlrdata != NULL);
    12432
    12433 /* collect statistics for nonlinear handlers */
    12434 SCIP_CALL( SCIPnlhdlrCollectStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, datatree) );
    12435
    12436 return SCIP_OKAY;
    12437}
    12438
    12439/** execution method of display nlhdlrs dialog */
    12440static
    12441SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
    12442{ /*lint --e{715}*/
    12443 SCIP_CONSHDLR* conshdlr;
    12444 SCIP_CONSHDLRDATA* conshdlrdata;
    12445 int i;
    12446
    12447 /* add dialog to history of dialogs that have been executed */
    12448 SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
    12449
    12450 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12451 assert(conshdlr != NULL);
    12452
    12453 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12454 assert(conshdlrdata != NULL);
    12455
    12456 /* display list of nonlinear handler */
    12457 SCIPdialogMessage(scip, NULL, "\n");
    12458 SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
    12459 SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
    12460 for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
    12461 {
    12462 SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
    12463 assert(nlhdlr != NULL);
    12464
    12465 SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
    12466 SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
    12469 SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
    12470 SCIPdialogMessage(scip, NULL, "\n");
    12471 }
    12472 SCIPdialogMessage(scip, NULL, "\n");
    12473
    12474 /* next dialog will be root dialog again */
    12475 *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
    12476
    12477 return SCIP_OKAY;
    12478}
    12479
    12480/*
    12481 * constraint handler specific interface methods
    12482 */
    12483
    12484/** creates the handler for nonlinear constraints and includes it in SCIP */
    12486 SCIP* scip /**< SCIP data structure */
    12487 )
    12488{
    12489 SCIP_CONSHDLRDATA* conshdlrdata;
    12490 SCIP_DIALOG* parentdialog;
    12491
    12492 /* create nonlinear constraint handler data */
    12493 SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
    12494 conshdlrdata->intevalvar = intEvalVarBoundTightening;
    12495 conshdlrdata->curboundstag = 1;
    12496 conshdlrdata->lastboundrelax = 1;
    12497 conshdlrdata->curpropboundstag = 1;
    12498 conshdlrdata->newsoleventfilterpos = -1;
    12499 SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
    12500 SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
    12501 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
    12502
    12503 /* include constraint handler */
    12509 conshdlrCopyNonlinear,
    12510 consFreeNonlinear, consInitNonlinear, consExitNonlinear,
    12511 consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
    12512 consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
    12513 consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
    12514 consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
    12515 consActiveNonlinear, consDeactiveNonlinear,
    12516 consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
    12517 consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
    12518 consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
    12519 consGetSignedPermsymGraphNonlinear, conshdlrdata) );
    12520
    12521 /* add nonlinear constraint handler parameters */
    12522 /* TODO organize into more subcategories */
    12523 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
    12524 "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
    12525 &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
    12526
    12527 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
    12528 "whether to check bounds of all auxiliary variable to seed reverse propagation",
    12529 &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
    12530
    12531 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
    12532 "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",
    12533 &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
    12534
    12535 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
    12536 "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
    12537 &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
    12538
    12539 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
    12540 "by how much to relax constraint sides during bound tightening",
    12541 &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
    12542
    12543 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
    12544 "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
    12545 &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
    12546
    12547 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
    12548 "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
    12549 &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
    12550
    12551 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
    12552 "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
    12553 &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
    12554
    12555 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
    12556 "maximal number of auxiliary expressions per bilinear term",
    12557 &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
    12558
    12559 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
    12560 "whether to reformulate products of binary variables during presolving",
    12561 &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
    12562
    12563 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
    12564 "whether to use the AND constraint handler for reformulating binary products",
    12565 &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
    12566
    12567 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
    12568 "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
    12569 &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
    12570
    12571 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
    12572 "whether to forbid multiaggregation of nonlinear variables",
    12573 &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
    12574
    12575 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
    12576 "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
    12577 &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
    12578
    12579 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
    12580 "whether to (re)run propagation in enforcement",
    12581 &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
    12582
    12583 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
    12584 "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
    12585 &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
    12586
    12587 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
    12588 "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
    12589 &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
    12590
    12591 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
    12592 "consider efficacy requirement when deciding whether a cut is \"strong\"",
    12593 &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
    12594
    12595 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
    12596 "whether to force \"strong\" cuts in enforcement",
    12597 &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
    12598
    12599 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
    12600 "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
    12601 &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
    12602
    12603 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
    12604 "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
    12605 &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
    12606
    12607 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
    12608 "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",
    12609 &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
    12610
    12611 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
    12612 "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
    12613 &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
    12614
    12615 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
    12616 "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)",
    12617 &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
    12618
    12619 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
    12620 "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
    12621 &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
    12622
    12623 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
    12624 "whether to use external branching candidates and branching rules for branching",
    12625 &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
    12626
    12627 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
    12628 "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
    12629 &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
    12630
    12631 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
    12632 "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
    12633 &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
    12634
    12635 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
    12636 "weight by how much to consider the violation assigned to a variable for its branching score",
    12637 &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12638
    12639 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
    12640 "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
    12641 &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12642
    12643 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
    12644 "weight by how much to consider the dual values of rows that contain a variable for its branching score",
    12645 &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12646
    12647 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
    12648 "weight by how much to consider the pseudo cost of a variable for its branching score",
    12649 &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12650
    12651 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
    12652 "weight by how much to consider the domain width in branching score",
    12653 &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12654
    12655 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
    12656 "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
    12657 &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12658
    12659 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
    12660 "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
    12661 &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
    12662
    12663 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
    12664 "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
    12665 &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
    12666
    12667 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
    12668 "minimum pseudo-cost update count required to consider pseudo-costs reliable",
    12669 &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
    12670
    12671 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
    12672 "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
    12673 &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
    12674
    12675 SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
    12676 "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)",
    12677 &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
    12678
    12679 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
    12680 "whether to assume that any constraint in the presolved problem is convex",
    12681 &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
    12682
    12683 /* include handler for bound change events */
    12684 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
    12685 "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
    12686 assert(conshdlrdata->eventhdlr != NULL);
    12687
    12688 /* include tables for statistics */
    12691 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear, tableCollectNonlinear,
    12693
    12696 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr, tableCollectNlhdlr,
    12698
    12699 /* create, include, and release display nlhdlrs dialog */
    12700 if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
    12701 {
    12702 SCIP_DIALOG* dialog;
    12703
    12704 assert(parentdialog != NULL);
    12705 assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
    12706
    12708 NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
    12710 SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
    12711 SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
    12712 }
    12713
    12714 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
    12715 processNewSolutionEvent, NULL) );
    12716
    12717 return SCIP_OKAY;
    12718}
    12719
    12720/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
    12722 SCIP* scip, /**< SCIP data structure */
    12723 SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
    12724 int priority, /**< priority of upgrading method */
    12725 SCIP_Bool active, /**< should the upgrading method by active by default? */
    12726 const char* conshdlrname /**< name of the constraint handler */
    12727 )
    12728{
    12729 SCIP_CONSHDLR* conshdlr;
    12730 SCIP_CONSHDLRDATA* conshdlrdata;
    12731 CONSUPGRADE* consupgrade;
    12733 char paramdesc[SCIP_MAXSTRLEN];
    12734 int i;
    12735
    12736 assert(conshdlrname != NULL );
    12737 assert(nlconsupgd != NULL);
    12738
    12739 /* find the nonlinear constraint handler */
    12740 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12741 if( conshdlr == NULL )
    12742 {
    12743 SCIPerrorMessage("nonlinear constraint handler not found\n");
    12744 return SCIP_PLUGINNOTFOUND;
    12745 }
    12746
    12747 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    12748 assert(conshdlrdata != NULL);
    12749
    12750 /* check whether upgrade method exists already */
    12751 for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
    12752 {
    12753 if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
    12754 {
    12755#ifdef SCIP_DEBUG
    12756 SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
    12757#endif
    12758 return SCIP_OKAY;
    12759 }
    12760 }
    12761
    12762 /* create a nonlinear constraint upgrade data object */
    12763 SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
    12764 consupgrade->consupgd = nlconsupgd;
    12765 consupgrade->priority = priority;
    12766 consupgrade->active = active;
    12767
    12768 /* insert nonlinear constraint upgrade method into constraint handler data */
    12769 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
    12770 assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
    12771
    12772 for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
    12773 conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
    12774 assert(0 <= i && i <= conshdlrdata->nconsupgrades);
    12775 conshdlrdata->consupgrades[i] = consupgrade;
    12776 conshdlrdata->nconsupgrades++;
    12777
    12778 /* adds parameter to turn on and off the upgrading step */
    12779 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
    12780 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
    12782 paramname, paramdesc,
    12783 &consupgrade->active, FALSE, active, NULL, NULL) );
    12784
    12785 return SCIP_OKAY;
    12786}
    12787
    12788/** creates and captures a nonlinear constraint
    12789 *
    12790 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12791 */
    12793 SCIP* scip, /**< SCIP data structure */
    12794 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12795 const char* name, /**< name of constraint */
    12796 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
    12797 SCIP_Real lhs, /**< left hand side of constraint */
    12798 SCIP_Real rhs, /**< right hand side of constraint */
    12799 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    12800 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    12801 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    12802 * Usually set to TRUE. */
    12803 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    12804 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12805 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    12806 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12807 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    12808 * Usually set to TRUE. */
    12809 SCIP_Bool local, /**< is constraint only valid locally?
    12810 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    12811 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    12812 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    12813 * adds coefficients to this constraint. */
    12814 SCIP_Bool dynamic, /**< is constraint subject to aging?
    12815 * Usually set to FALSE. Set to TRUE for own cuts which
    12816 * are separated as constraints. */
    12817 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
    12818 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    12819 )
    12820{
    12821 /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
    12822 SCIP_CONSHDLR* conshdlr;
    12823
    12824 /* find the nonlinear constraint handler */
    12825 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12826 if( conshdlr == NULL )
    12827 {
    12828 SCIPerrorMessage("nonlinear constraint handler not found\n");
    12829 return SCIP_PLUGINNOTFOUND;
    12830 }
    12831
    12832 /* create constraint */
    12833 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
    12834 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12835
    12836 return SCIP_OKAY;
    12837}
    12838
    12839/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
    12840 *
    12841 * All flags can be set via SCIPconsSetFLAGNAME-methods.
    12842 *
    12843 * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
    12844 *
    12845 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12846 */
    12848 SCIP* scip, /**< SCIP data structure */
    12849 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12850 const char* name, /**< name of constraint */
    12851 SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
    12852 SCIP_Real lhs, /**< left hand side of constraint */
    12853 SCIP_Real rhs /**< right hand side of constraint */
    12854 )
    12855{
    12856 SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
    12858
    12859 return SCIP_OKAY;
    12860}
    12861
    12862/** creates and captures a quadratic nonlinear constraint
    12863 *
    12864 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12865 */
    12867 SCIP* scip, /**< SCIP data structure */
    12868 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12869 const char* name, /**< name of constraint */
    12870 int nlinvars, /**< number of linear terms */
    12871 SCIP_VAR** linvars, /**< array with variables in linear part */
    12872 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
    12873 int nquadterms, /**< number of quadratic terms */
    12874 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
    12875 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
    12876 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
    12877 SCIP_Real lhs, /**< left hand side of quadratic equation */
    12878 SCIP_Real rhs, /**< right hand side of quadratic equation */
    12879 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
    12880 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
    12881 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
    12882 * Usually set to TRUE. */
    12883 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
    12884 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12885 SCIP_Bool check, /**< should the constraint be checked for feasibility?
    12886 * TRUE for model constraints, FALSE for additional, redundant constraints. */
    12887 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
    12888 * Usually set to TRUE. */
    12889 SCIP_Bool local, /**< is constraint only valid locally?
    12890 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
    12891 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
    12892 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
    12893 * adds coefficients to this constraint. */
    12894 SCIP_Bool dynamic, /**< is constraint subject to aging?
    12895 * Usually set to FALSE. Set to TRUE for own cuts which
    12896 * are separated as constraints. */
    12897 SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
    12898 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
    12899 )
    12900{
    12901 SCIP_CONSHDLR* conshdlr;
    12902 SCIP_EXPR* expr;
    12903 int i;
    12904
    12905 assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
    12906 assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
    12907
    12908 /* check data for infinity or nan values */
    12909 for( i = 0; i < nlinvars; ++i )
    12910 {
    12911 if( !SCIPisFinite(lincoefs[i]) || SCIPisInfinity(scip, lincoefs[i]) )
    12912 {
    12913 SCIPerrorMessage("Infinite or nan coefficient of variable %s in quadratic constraint %s\n", SCIPvarGetName(linvars[i]), name);
    12914 return SCIP_INVALIDDATA;
    12915 }
    12916 }
    12917 for( i = 0; i < nquadterms; ++i )
    12918 {
    12919 if( !SCIPisFinite(quadcoefs[i]) || SCIPisInfinity(scip, quadcoefs[i]) )
    12920 {
    12921 SCIPerrorMessage("Infinite or nan coefficient of term %s*%s in quadratic constraint %s\n", SCIPvarGetName(quadvars1[i]), SCIPvarGetName(quadvars2[i]), name);
    12922 return SCIP_INVALIDDATA;
    12923 }
    12924 }
    12925 /* lhs and rhs will be checked in createCons */
    12926
    12927 /* get nonlinear constraint handler */
    12928 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    12929 if( conshdlr == NULL )
    12930 {
    12931 SCIPerrorMessage("nonlinear constraint handler not found\n");
    12932 return SCIP_PLUGINNOTFOUND;
    12933 }
    12934
    12935 /* create quadratic expression */
    12936 SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
    12937 assert(expr != NULL);
    12938
    12939 /* create nonlinear constraint */
    12940 SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
    12941 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
    12942
    12943 /* release quadratic expression (captured by constraint now) */
    12944 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
    12945
    12946 return SCIP_OKAY;
    12947}
    12948
    12949/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
    12950 *
    12951 * All flags can be set via SCIPconsSetFLAGNAME-methods.
    12952 *
    12953 * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
    12954 *
    12955 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12956 */
    12958 SCIP* scip, /**< SCIP data structure */
    12959 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12960 const char* name, /**< name of constraint */
    12961 int nlinvars, /**< number of linear terms */
    12962 SCIP_VAR** linvars, /**< array with variables in linear part */
    12963 SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
    12964 int nquadterms, /**< number of quadratic terms */
    12965 SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
    12966 SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
    12967 SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
    12968 SCIP_Real lhs, /**< left hand side of quadratic equation */
    12969 SCIP_Real rhs /**< right hand side of quadratic equation */
    12970 )
    12971{
    12972 SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
    12974
    12975 return SCIP_OKAY;
    12976}
    12977
    12978/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
    12979 *
    12980 * \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$
    12981 *
    12982 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    12983 */
    12985 SCIP* scip, /**< SCIP data structure */
    12986 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    12987 const char* name, /**< name of constraint */
    12988 int nvars, /**< number of variables on left hand side of constraint (n) */
    12989 SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
    12990 SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
    12991 SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
    12992 SCIP_Real constant, /**< constant on left hand side (gamma) */
    12993 SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
    12994 SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
    12995 SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
    12996 )
    12997{
    12998 SCIP_EXPR* expr;
    12999 SCIP_EXPR* lhssum;
    13000 SCIP_EXPR* terms[2];
    13001 SCIP_Real termcoefs[2];
    13002 int i;
    13003
    13004 assert(vars != NULL || nvars == 0);
    13005
    13006 /* check values for infinity or nan */
    13007 for( i = 0; i < nvars; ++i )
    13008 {
    13009 if( !SCIPisFinite(coefs[i]) || SCIPisInfinity(scip, coefs[i]) )
    13010 {
    13011 SCIPerrorMessage("Second-order cone term with infinite or nan coefficient of variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
    13012 return SCIP_INVALIDDATA;
    13013 }
    13014 if( offsets != NULL && (!SCIPisFinite(offsets[i]) || SCIPisInfinity(scip, coefs[i])) )
    13015 {
    13016 SCIPerrorMessage("Second-order cone term with infinite or nan offset for variable %s in nonlinear constraint %s\n", SCIPvarGetName(vars[i]), name);
    13017 return SCIP_INVALIDDATA;
    13018 }
    13019 }
    13020 if( !SCIPisFinite(constant) || SCIPisInfinity(scip, constant) )
    13021 {
    13022 SCIPerrorMessage("Second-order cone constant with infinite or nan value in nonlinear constraint %s\n", name);
    13023 return SCIP_INVALIDDATA;
    13024 }
    13025 if( !SCIPisFinite(rhscoeff) || SCIPisInfinity(scip, rhscoeff) )
    13026 {
    13027 SCIPerrorMessage("Infinite or nan coefficient of right hand side variable in second-order cone constraint %s\n", name);
    13028 return SCIP_INVALIDDATA;
    13029 }
    13030 if( !SCIPisFinite(rhsoffset) || SCIPisInfinity(scip, rhsoffset) )
    13031 {
    13032 SCIPerrorMessage("Infinite or nan right hand side offset in second-order cone constraint %s\n", name);
    13033 return SCIP_INVALIDDATA;
    13034 }
    13035 /* lhs and rhs will be checked in createCons */
    13036
    13037 SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
    13038 for( i = 0; i < nvars; ++i )
    13039 {
    13040 SCIP_EXPR* varexpr;
    13041 SCIP_EXPR* powexpr;
    13042
    13043 SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
    13044 if( offsets != NULL && offsets[i] != 0.0 )
    13045 {
    13046 SCIP_EXPR* sum;
    13047 SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
    13048 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
    13049 SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
    13050 }
    13051 else
    13052 {
    13053 SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
    13054 }
    13055
    13056 SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
    13057 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
    13058 SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
    13059 }
    13060
    13061 SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
    13062 SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
    13063 termcoefs[0] = 1.0;
    13064
    13065 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
    13066 termcoefs[1] = -rhscoeff;
    13067
    13068 SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
    13069
    13070 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
    13071 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
    13072
    13073 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
    13074
    13075 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
    13076
    13077 return SCIP_OKAY;
    13078}
    13079
    13080/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
    13081 *
    13082 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
    13083 *
    13084 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
    13085 */
    13087 SCIP* scip, /**< SCIP data structure */
    13088 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    13089 const char* name, /**< name of constraint */
    13090 SCIP_VAR* x, /**< nonlinear variable x in constraint */
    13091 SCIP_VAR* z, /**< linear variable z in constraint */
    13092 SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
    13093 SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
    13094 SCIP_Real zcoef, /**< coefficient of z in constraint */
    13095 SCIP_Real lhs, /**< left hand side of constraint */
    13096 SCIP_Real rhs /**< right hand side of constraint */
    13097 )
    13098{
    13099 SCIP_EXPR* xexpr;
    13100 SCIP_EXPR* terms[2];
    13101 SCIP_Real coefs[2];
    13102 SCIP_EXPR* sumexpr;
    13103
    13104 assert(x != NULL);
    13105 assert(z != NULL);
    13106
    13107 if( !SCIPisFinite(exponent) )
    13108 {
    13109 SCIPerrorMessage("exponent in nonlinear signpower constraint <%s> is infinite or nan\n", name);
    13110 return SCIP_INVALIDDATA;
    13111 }
    13112
    13113 if( !SCIPisFinite(xoffset) )
    13114 {
    13115 SCIPerrorMessage("argument offset in nonlinear signpower constraint <%s> is infinite or nan\n", name);
    13116 return SCIP_INVALIDDATA;
    13117 }
    13118
    13119 if( !SCIPisFinite(zcoef) )
    13120 {
    13121 SCIPerrorMessage("coefficient of linear variable in nonlinear signpower constraint <%s> is infinite or nan\n", name);
    13122 return SCIP_INVALIDDATA;
    13123 }
    13124
    13125 SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
    13126 if( xoffset != 0.0 )
    13127 {
    13128 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
    13129 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
    13130
    13131 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
    13132 }
    13133 else
    13134 {
    13135 SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
    13136 }
    13137 coefs[0] = 1.0;
    13138
    13139 SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
    13140 coefs[1] = zcoef;
    13141
    13142 SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
    13143
    13144 SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
    13145
    13146 SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
    13147 SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
    13148 SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
    13149 SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
    13150
    13151 return SCIP_OKAY;
    13152}
    13153
    13154/** gets tag indicating current local variable bounds */
    13156 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13157 )
    13158{
    13159 SCIP_CONSHDLRDATA* conshdlrdata;
    13160
    13161 assert(conshdlr != NULL);
    13162 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13163
    13164 return conshdlrdata->curboundstag;
    13165}
    13166
    13167/** gets the `curboundstag` from the last time where variable bounds were relaxed */
    13169 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13170 )
    13171{
    13172 SCIP_CONSHDLRDATA* conshdlrdata;
    13173
    13174 assert(conshdlr != NULL);
    13175 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13176
    13177 return conshdlrdata->lastboundrelax;
    13178}
    13179
    13180/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
    13181 *
    13182 * @attention This method is not intended for normal use.
    13183 * These tags are maintained by the event handler for variable bound change events.
    13184 * This method is used by some unittests.
    13185 */
    13187 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13188 SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
    13189 )
    13190{
    13191 SCIP_CONSHDLRDATA* conshdlrdata;
    13192
    13193 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13194 assert(conshdlrdata != NULL);
    13195
    13196 ++conshdlrdata->curboundstag;
    13197 assert(conshdlrdata->curboundstag > 0);
    13198
    13199 if( boundrelax )
    13200 conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
    13201}
    13202
    13203/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
    13205 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13206 )
    13207{
    13208 assert(conshdlr != NULL);
    13209
    13210 return SCIPconshdlrGetData(conshdlr)->var2expr;
    13211}
    13212
    13213/** processes a rowprep for cut addition and maybe report branchscores */
    13215 SCIP* scip, /**< SCIP data structure */
    13216 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
    13217 SCIP_CONS* cons, /**< nonlinear constraint */
    13218 SCIP_EXPR* expr, /**< expression */
    13219 SCIP_ROWPREP* rowprep, /**< cut to be added */
    13220 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
    13221 SCIP_VAR* auxvar, /**< auxiliary variable */
    13222 SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
    13223 SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
    13224 SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
    13225 SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
    13226 SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
    13227 SCIP_RESULT* result /**< pointer to store the result */
    13228 )
    13229{
    13230 SCIP_Real cutviol;
    13231 SCIP_CONSHDLRDATA* conshdlrdata;
    13232 SCIP_Real auxvarvalue = SCIP_INVALID;
    13233 SCIP_Bool sepasuccess;
    13234 SCIP_Real estimateval = SCIP_INVALID;
    13235 SCIP_Real mincutviolation;
    13236
    13237 assert(nlhdlr != NULL);
    13238 assert(cons != NULL);
    13239 assert(expr != NULL);
    13240 assert(rowprep != NULL);
    13241 assert(auxvar != NULL);
    13242 assert(result != NULL);
    13243
    13244 /* decide on minimal violation of cut */
    13245 if( sol == NULL )
    13246 mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
    13247 else
    13248 mincutviolation = SCIPfeastol(scip);
    13249
    13250 conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
    13251 assert(conshdlrdata != NULL);
    13252
    13253 sepasuccess = TRUE;
    13254
    13255 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
    13256 if( cutviol > 0.0 )
    13257 {
    13258 auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
    13259
    13260 /* check whether cut is weak (if f(x) not defined, then it's never weak) */
    13261 if( !allowweakcuts && auxvalue != SCIP_INVALID )
    13262 {
    13263 /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
    13264 * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
    13265 * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
    13266 * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
    13267 * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
    13268 * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
    13269 *
    13270 * if we are overestimating, we have z >= c'x-b >= f(x)
    13271 * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
    13272 * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
    13273 * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
    13274 *
    13275 * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
    13276 */
    13277 if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
    13278 ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
    13279 {
    13280 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
    13281 "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
    13282 SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
    13283 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
    13284 sepasuccess = FALSE;
    13285 }
    13286 }
    13287
    13288 /* save estimator value for later, see long comment above why this gives the value for c'x-b */
    13289 estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
    13290 }
    13291 else
    13292 {
    13293 sepasuccess = FALSE;
    13294 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
    13295 "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
    13296 }
    13297
    13298 /* clean up estimator */
    13299 if( sepasuccess )
    13300 {
    13301 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
    13302 "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
    13303 auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
    13304 SCIPprintRowprep(scip, rowprep, enfologfile); )
    13305
    13306 /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
    13307 * instead, may even scale them down, that is, scale so that max coef is close to 1
    13308 */
    13309 if( !allowweakcuts )
    13310 {
    13311 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
    13312
    13313 if( !sepasuccess )
    13314 {
    13315 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
    13316 }
    13317 else
    13318 {
    13319 cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
    13320 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
    13321 "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
    13322 if( sepasuccess )
    13323 sepasuccess = cutviol > mincutviolation;
    13324 }
    13325
    13326 if( sepasuccess && auxvalue != SCIP_INVALID )
    13327 {
    13328 /* check whether cut is weak now
    13329 * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
    13330 * reconstructing estimateval from cutviol (TODO improve or remove?)
    13331 */
    13332 SCIP_Real auxvarcoef = 0.0;
    13333 int i;
    13334
    13335 /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
    13336 * it should be...
    13337 */
    13338 for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
    13339 {
    13340 if( SCIProwprepGetVars(rowprep)[i] == auxvar )
    13341 {
    13342 auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
    13343 break;
    13344 }
    13345 }
    13346
    13347 if( auxvarcoef == 0.0 ||
    13348 (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
    13349 ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
    13350 {
    13351 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
    13352 auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
    13353 sepasuccess = FALSE;
    13354 }
    13355 }
    13356 }
    13357 else
    13358 {
    13359 /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
    13360
    13361 /* if estimate didn't report branchscores explicitly, then consider branching on those children for
    13362 * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
    13363 */
    13364 if( !branchscoresuccess )
    13366
    13367 SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
    13368
    13369 if( !sepasuccess )
    13370 {
    13371 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
    13372 SCIProwprepGetNModifiedVars(rowprep), cutviol); )
    13373 }
    13374
    13375 /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
    13376 * changed
    13377 */
    13378 if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
    13379 {
    13380 SCIP_Real violscore;
    13381
    13382#ifdef BRSCORE_ABSVIOL
    13383 violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
    13384#else
    13385 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
    13386#endif
    13387 SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
    13388
    13389 /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
    13390 * - were fixed,
    13391 * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
    13392 * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
    13393 * the first case came up again in #3085 and I don't see how to exclude this in the assert,
    13394 * so I'm disabling the assert for now
    13395 */
    13396 /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
    13397 strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
    13398 }
    13399 }
    13400 }
    13401
    13402 /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
    13403 if( sepasuccess )
    13404 {
    13405 SCIP_ROW* row;
    13406
    13407 if( conshdlrdata->branchdualweight > 0.0 )
    13408 {
    13409 /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
    13410 * skip if gap is zero
    13411 */
    13412 if( auxvalue == SCIP_INVALID )
    13413 strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
    13414 else if( !SCIPisEQ(scip, auxvalue, estimateval) )
    13415 {
    13416 char gap[40];
    13417 /* coverity[secure_coding] */
    13418 (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
    13419 strcat(SCIProwprepGetName(rowprep), gap);
    13420 }
    13421 }
    13422
    13423 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
    13424
    13425 if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
    13426 {
    13427 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
    13429 }
    13430 else if( !SCIPisCutApplicable(scip, row) )
    13431 {
    13432 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
    13433 }
    13434 else
    13435 {
    13436 SCIP_Bool infeasible;
    13437
    13438 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
    13439 SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
    13440
    13441 /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
    13442 * if we haven't found strong cuts before)
    13443 */
    13444 SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
    13445
    13446 /* mark row as not removable from LP for current node (this can prevent some cycling) */
    13447 if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
    13449
    13450 if( infeasible )
    13451 {
    13452 *result = SCIP_CUTOFF;
    13454 }
    13455 else
    13456 {
    13457 *result = SCIP_SEPARATED;
    13459 }
    13460 }
    13461
    13462 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    13463 }
    13464 else if( branchscoresuccess )
    13465 {
    13466 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
    13467 "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
    13468
    13469 /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
    13470 * expressions eligible for branching candidate, see enforceConstraints() and branching()
    13471 */
    13472 *result = SCIP_BRANCHED;
    13473 }
    13474 else
    13475 {
    13476 ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
    13477 "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
    13478 " (!)" : ""); )
    13479 }
    13480
    13481 return SCIP_OKAY;
    13482}
    13483
    13484/** returns whether all nonlinear constraints are assumed to be convex */
    13486 SCIP_CONSHDLR* conshdlr
    13487 )
    13488{
    13489 SCIP_CONSHDLRDATA* conshdlrdata;
    13490
    13491 assert(conshdlr != NULL);
    13492
    13493 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13494 assert(conshdlrdata != NULL);
    13495
    13496 return conshdlrdata->assumeconvex;
    13497}
    13498
    13499/** collects all bilinear terms for a given set of constraints
    13500 *
    13501 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
    13502 * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
    13503 */
    13505 SCIP* scip, /**< SCIP data structure */
    13506 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13507 SCIP_CONS** conss, /**< nonlinear constraints */
    13508 int nconss /**< total number of nonlinear constraints */
    13509 )
    13510{
    13511 assert(conshdlr != NULL);
    13512 assert(conss != NULL || nconss == 0);
    13513
    13514 SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
    13515
    13516 return SCIP_OKAY;
    13517}
    13518
    13519/** returns the total number of bilinear terms that are contained in all nonlinear constraints
    13520 *
    13521 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13522 */
    13524 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13525 )
    13526{
    13527 SCIP_CONSHDLRDATA* conshdlrdata;
    13528
    13529 assert(conshdlr != NULL);
    13530
    13531 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13532 assert(conshdlrdata != NULL);
    13533
    13534 return conshdlrdata->nbilinterms;
    13535}
    13536
    13537/** returns all bilinear terms that are contained in all nonlinear constraints
    13538 *
    13539 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13540 * @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.
    13541 */
    13543 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    13544 )
    13545{
    13546 SCIP_CONSHDLRDATA* conshdlrdata;
    13547
    13548 assert(conshdlr != NULL);
    13549
    13550 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13551 assert(conshdlrdata != NULL);
    13552
    13553 return conshdlrdata->bilinterms;
    13554}
    13555
    13556/** returns the index of the bilinear term representing the product of the two given variables
    13557 *
    13558 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13559 * @return The method returns -1 if the variables do not appear bilinearly.
    13560 */
    13562 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13563 SCIP_VAR* x, /**< first variable */
    13564 SCIP_VAR* y /**< second variable */
    13565 )
    13566{
    13567 SCIP_CONSHDLRDATA* conshdlrdata;
    13569 int idx;
    13570
    13571 assert(conshdlr != NULL);
    13572 assert(x != NULL);
    13573 assert(y != NULL);
    13574
    13575 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13576 assert(conshdlrdata != NULL);
    13577
    13578 if( conshdlrdata->bilinhashtable == NULL )
    13579 {
    13580 return -1;
    13581 }
    13582
    13583 /* ensure that x.index <= y.index */
    13584 if( SCIPvarCompare(x, y) == 1 )
    13585 {
    13586 SCIPswapPointers((void**)&x, (void**)&y);
    13587 }
    13588 assert(SCIPvarCompare(x, y) < 1);
    13589
    13590 /* use a new entry to find the image in the bilinear hash table */
    13591 entry.x = x;
    13592 entry.y = y;
    13593 idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
    13594 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
    13595 assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
    13596 assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
    13597
    13598 return idx;
    13599}
    13600
    13601/** returns the bilinear term that represents the product of two given variables
    13602 *
    13603 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
    13604 * @return The method returns NULL if the variables do not appear bilinearly.
    13605 */
    13607 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13608 SCIP_VAR* x, /**< first variable */
    13609 SCIP_VAR* y /**< second variable */
    13610 )
    13611{
    13612 SCIP_CONSHDLRDATA* conshdlrdata;
    13613 int idx;
    13614
    13615 assert(conshdlr != NULL);
    13616 assert(x != NULL);
    13617 assert(y != NULL);
    13618
    13619 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13620 assert(conshdlrdata != NULL);
    13621
    13622 idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
    13623 assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
    13624
    13625 if( idx >= 0 )
    13626 {
    13627 return &conshdlrdata->bilinterms[idx];
    13628 }
    13629
    13630 return NULL;
    13631}
    13632
    13633/** evaluates an auxiliary expression for a bilinear term */
    13635 SCIP* scip, /**< SCIP data structure */
    13636 SCIP_VAR* x, /**< first variable of the bilinear term */
    13637 SCIP_VAR* y, /**< second variable of the bilinear term */
    13638 SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
    13639 SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
    13640 )
    13641{
    13642 assert(scip != NULL);
    13643 assert(x != NULL);
    13644 assert(y != NULL);
    13645 assert(auxexpr != NULL);
    13646 assert(auxexpr->auxvar != NULL);
    13647
    13648 return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
    13649 auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
    13650}
    13651
    13652/** stores the variables of a bilinear term in the data of the constraint handler */
    13654 SCIP* scip, /**< SCIP data structure */
    13655 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    13656 SCIP_VAR* x, /**< first variable */
    13657 SCIP_VAR* y, /**< second variable */
    13658 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
    13659 int nlockspos, /**< number of positive expression locks */
    13660 int nlocksneg /**< number of negative expression locks */
    13661 )
    13662{
    13663 SCIP_CONSHDLRDATA* conshdlrdata;
    13665 int idx;
    13666
    13667 assert(conshdlr != NULL);
    13668
    13669 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13670 assert(conshdlrdata != NULL);
    13671
    13672 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
    13673
    13674 term = &conshdlrdata->bilinterms[idx];
    13675 assert(term != NULL);
    13676 assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
    13677 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) */
    13678
    13679 /* store and capture auxiliary variable */
    13680 if( auxvar != NULL )
    13681 {
    13682 term->aux.var = auxvar;
    13683 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
    13684 }
    13685
    13686 return SCIP_OKAY;
    13687}
    13688
    13689/** stores the variables of a bilinear term in the data of the constraint handler */
    13691 SCIP* scip, /**< SCIP data structure */
    13692 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    13693 SCIP_VAR* x, /**< first variable */
    13694 SCIP_VAR* y, /**< second variable */
    13695 SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
    13696 SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
    13697 SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
    13698 SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
    13699 SCIP_Real cst, /**< constant of the auxiliary expression */
    13700 SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
    13701 )
    13702{
    13703 SCIP_CONSHDLRDATA* conshdlrdata;
    13706 int idx;
    13707 int nlockspos;
    13708 int nlocksneg;
    13709 SCIP_Bool added;
    13710
    13711 assert(conshdlr != NULL);
    13712
    13713 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13714 assert(conshdlrdata != NULL);
    13715
    13716 nlockspos = overestimate ? 1 : 0;
    13717 nlocksneg = overestimate ? 0 : 1;
    13718
    13719 SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
    13720
    13721 term = &conshdlrdata->bilinterms[idx];
    13722 assert(term != NULL);
    13723 assert(SCIPvarCompare(term->x, term->y) < 1);
    13724
    13725 if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
    13726 {
    13727 SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
    13728 /* this is the case where we are adding an implicitly defined relation for a product that has already
    13729 * been explicitly defined; convert auxvar into an auxexpr */
    13730
    13731 /* nothing to do if we aren't allowed to add more than one auxexpr per term */
    13732 if( conshdlrdata->bilinmaxnauxexprs <= 1 )
    13733 return SCIP_OKAY;
    13734
    13735 SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
    13736 auxvarexpr->cst = 0.0;
    13737 auxvarexpr->coefs[0] = 1.0;
    13738 auxvarexpr->coefs[1] = 0.0;
    13739 auxvarexpr->coefs[2] = 0.0;
    13740 auxvarexpr->auxvar = term->aux.var;
    13741 auxvarexpr->underestimate = term->nlocksneg > 0;
    13742 auxvarexpr->overestimate = term->nlockspos > 0;
    13743
    13744 /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
    13745 term->aux.exprs = NULL;
    13746
    13747 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
    13748
    13749 /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
    13750 assert(added);
    13751 }
    13752
    13753 /* create and add auxexpr */
    13754 SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
    13755 auxexpr->underestimate = !overestimate;
    13756 auxexpr->overestimate = overestimate;
    13757 auxexpr->auxvar = auxvar;
    13758 auxexpr->coefs[0] = coefaux;
    13759 if( term->x == x )
    13760 {
    13761 assert(term->y == y);
    13762 auxexpr->coefs[1] = coefx;
    13763 auxexpr->coefs[2] = coefy;
    13764 }
    13765 else
    13766 {
    13767 assert(term->x == y);
    13768 assert(term->y == x);
    13769 auxexpr->coefs[1] = coefy;
    13770 auxexpr->coefs[2] = coefx;
    13771 }
    13772 auxexpr->cst = cst;
    13773 SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
    13774
    13775 if( !added )
    13776 {
    13777 SCIPfreeBlockMemory(scip, &auxexpr);
    13778 }
    13779 else if( auxvar != NULL )
    13780 { /* capture auxiliary variable */
    13781 SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
    13782 }
    13783
    13784 return SCIP_OKAY;
    13785}
    13786
    13787/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
    13789 SCIP* scip, /**< SCIP data structure */
    13790 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    13791 SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
    13792 SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
    13793 void* fundata, /**< data for function evaluation (can be NULL) */
    13794 SCIP_Real* xstar, /**< point to be separated */
    13795 SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
    13796 int nallvars, /**< half of the length of box */
    13797 SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
    13798 SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
    13799 SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
    13800 SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
    13801 )
    13802{
    13803 SCIP_Real* corner;
    13804 SCIP_Real* funvals;
    13805 int* nonfixedpos;
    13806 SCIP_Real maxfaceterror;
    13807 int nvars; /* number of nonfixed variables */
    13808 unsigned int ncorners;
    13809 unsigned int i;
    13810 int j;
    13811
    13812 assert(scip != NULL);
    13813 assert(conshdlr != NULL);
    13814 assert(function != NULL);
    13815 assert(xstar != NULL);
    13816 assert(box != NULL);
    13817 assert(success != NULL);
    13818 assert(facetcoefs != NULL);
    13819 assert(facetconstant != NULL);
    13820
    13821 *success = FALSE;
    13822
    13823 /* identify fixed variables */
    13824 SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
    13825 nvars = 0;
    13826 for( j = 0; j < nallvars; ++j )
    13827 {
    13828 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
    13829 continue;
    13830 nonfixedpos[nvars] = j;
    13831 nvars++;
    13832 }
    13833
    13834 /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
    13835 * if too many variables are not fixed, then we do nothing currently
    13836 */
    13837 if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
    13838 {
    13839 SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
    13840 SCIPfreeBufferArray(scip, &nonfixedpos);
    13841 return SCIP_OKAY;
    13842 }
    13843
    13844 /* compute f(v^i) for each corner v^i of [l,u] */
    13845 ncorners = POWEROFTWO(nvars);
    13846 SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
    13847 SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
    13848 for( j = 0; j < nallvars; ++j )
    13849 {
    13850 if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
    13851 corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
    13852 }
    13853 for( i = 0; i < ncorners; ++i )
    13854 {
    13855 SCIPdebugMsg(scip, "corner %u: ", i);
    13856 for( j = 0; j < nvars; ++j )
    13857 {
    13858 int varpos = nonfixedpos[j];
    13859 /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
    13860 * we check this by shifting i for j positions to the right and checking whether the last bit is set
    13861 */
    13862 if( (i >> j) & 0x1 )
    13863 corner[varpos] = box[2 * varpos + 1]; /* ub of var */
    13864 else
    13865 corner[varpos] = box[2 * varpos ]; /* lb of var */
    13866 SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
    13867 assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
    13868 }
    13869
    13870 funvals[i] = function(corner, nallvars, fundata);
    13871
    13872 SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
    13873
    13874 if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
    13875 {
    13876 SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
    13877 goto CLEANUP;
    13878 }
    13879 }
    13880
    13881 /* clear coefs array; below we only fill in coefs for nonfixed variables */
    13882 BMSclearMemoryArray(facetcoefs, nallvars);
    13883
    13884 if( nvars == 1 )
    13885 {
    13886 SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
    13887
    13888 /* check whether target has been missed */
    13889 if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
    13890 {
    13891 SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
    13892 *success = FALSE;
    13893 }
    13894 }
    13895 else if( nvars == 2 && SCIPlapackIsAvailable() )
    13896 {
    13897 int idx1 = nonfixedpos[0];
    13898 int idx2 = nonfixedpos[1];
    13899 SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
    13900 SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
    13901 SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
    13902 SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
    13903 SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
    13904 SCIP_Real coefs[2] = { 0.0, 0.0 };
    13905
    13906 SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
    13907
    13908 facetcoefs[idx1] = coefs[0];
    13909 facetcoefs[idx2] = coefs[1];
    13910 }
    13911 else
    13912 {
    13913 SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
    13914 }
    13915 if( !*success )
    13916 {
    13917 SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
    13918 goto CLEANUP;
    13919 }
    13920
    13921 /*
    13922 * check and adjust facet with the algorithm of Rikun et al.
    13923 */
    13924
    13925 maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
    13926
    13927 /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
    13928 if( maxfaceterror > 0.0 )
    13929 {
    13930 SCIP_CONSHDLRDATA* conshdlrdata;
    13931 SCIP_Real midval;
    13932 SCIP_Real feastol;
    13933
    13935
    13936 /* evaluate function in middle point to get some idea for a scaling */
    13937 for( j = 0; j < nvars; ++j )
    13938 corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
    13939 midval = function(corner, nallvars, fundata);
    13940 if( midval == SCIP_INVALID )
    13941 midval = 1.0;
    13942
    13943 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    13944 assert(conshdlrdata != NULL);
    13945
    13946 /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
    13947 if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
    13948 {
    13949 SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
    13950 *success = FALSE;
    13951 goto CLEANUP;
    13952 }
    13953
    13954 SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
    13955
    13956 if( overestimate )
    13957 *facetconstant += maxfaceterror;
    13958 else
    13959 *facetconstant -= maxfaceterror;
    13960 }
    13961
    13962 /* if we made it until here, then we have a nice facet */
    13963 assert(*success);
    13964
    13965CLEANUP:
    13966 /* free allocated memory */
    13967 SCIPfreeBufferArray(scip, &corner);
    13968 SCIPfreeBufferArray(scip, &funvals);
    13969 SCIPfreeBufferArray(scip, &nonfixedpos);
    13970
    13971 return SCIP_OKAY;
    13972}
    13973
    13974/*
    13975 * constraint specific interface methods
    13976 */
    13977
    13978/** returns the expression of the given nonlinear constraint */
    13980 SCIP_CONS* cons /**< constraint data */
    13981 )
    13982{
    13983 SCIP_CONSDATA* consdata;
    13984
    13985 assert(cons != NULL);
    13986 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    13987
    13988 consdata = SCIPconsGetData(cons);
    13989 assert(consdata != NULL);
    13990
    13991 return consdata->expr;
    13992}
    13993
    13994/** gets the left hand side of a nonlinear constraint */
    13996 SCIP_CONS* cons /**< constraint data */
    13997 )
    13998{
    13999 SCIP_CONSDATA* consdata;
    14000
    14001 assert(cons != NULL);
    14002 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14003
    14004 consdata = SCIPconsGetData(cons);
    14005 assert(consdata != NULL);
    14006
    14007 return consdata->lhs;
    14008}
    14009
    14010/** gets the right hand side of a nonlinear constraint */
    14012 SCIP_CONS* cons /**< constraint data */
    14013 )
    14014{
    14015 SCIP_CONSDATA* consdata;
    14016
    14017 assert(cons != NULL);
    14018 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14019
    14020 consdata = SCIPconsGetData(cons);
    14021 assert(consdata != NULL);
    14022
    14023 return consdata->rhs;
    14024}
    14025
    14026/** gets the nonlinear constraint as a nonlinear row representation. */
    14028 SCIP* scip, /**< SCIP data structure */
    14029 SCIP_CONS* cons, /**< constraint */
    14030 SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
    14031 )
    14032{
    14033 SCIP_CONSDATA* consdata;
    14034
    14035 assert(cons != NULL);
    14036 assert(nlrow != NULL);
    14037 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14038
    14039 consdata = SCIPconsGetData(cons);
    14040 assert(consdata != NULL);
    14041
    14042 if( consdata->nlrow == NULL )
    14043 {
    14044 SCIP_CALL( createNlRow(scip, cons) );
    14045 }
    14046 assert(consdata->nlrow != NULL);
    14047 *nlrow = consdata->nlrow;
    14048
    14049 return SCIP_OKAY;
    14050}
    14051
    14052/** returns the curvature of the expression of a given nonlinear constraint
    14053 *
    14054 * @note The curvature information is computed during CONSINITSOL.
    14055 */
    14057 SCIP_CONS* cons /**< constraint data */
    14058 )
    14059{
    14060 SCIP_CONSDATA* consdata;
    14061
    14062 assert(cons != NULL);
    14063 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14064
    14065 consdata = SCIPconsGetData(cons);
    14066 assert(consdata != NULL);
    14067
    14068 return consdata->curv;
    14069}
    14070
    14071/** checks whether expression of constraint can be represented as quadratic form
    14072 *
    14073 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
    14074 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
    14075 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
    14076 */
    14078 SCIP* scip, /**< SCIP data structure */
    14079 SCIP_CONS* cons, /**< constraint data */
    14080 SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
    14081 )
    14082{
    14083 SCIP_CONSDATA* consdata;
    14084
    14085 assert(scip != NULL);
    14086 assert(cons != NULL);
    14087 assert(isquadratic != NULL);
    14088 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14089
    14090 consdata = SCIPconsGetData(cons);
    14091 assert(consdata != NULL);
    14092 assert(consdata->expr != NULL);
    14093
    14094 /* check whether constraint expression is quadratic in extended formulation */
    14095 SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
    14096
    14097 /* if not quadratic in non-extended formulation, then do indicate quadratic */
    14098 if( *isquadratic )
    14099 *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
    14100
    14101 return SCIP_OKAY;
    14102}
    14103
    14104/** changes left-hand-side of a nonlinear constraint
    14105 *
    14106 * @attention This method can only be called in the problem stage.
    14107 */
    14109 SCIP* scip, /**< SCIP data structure */
    14110 SCIP_CONS* cons, /**< constraint data */
    14111 SCIP_Real lhs /**< new left-hand-side */
    14112 )
    14113{
    14114 SCIP_CONSDATA* consdata;
    14115
    14116 assert(scip != NULL);
    14117 assert(cons != NULL);
    14118 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14119
    14121 {
    14122 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
    14123 return SCIP_INVALIDCALL;
    14124 }
    14125
    14126 /* we should have an original constraint */
    14127 assert(SCIPconsIsOriginal(cons));
    14128
    14129 consdata = SCIPconsGetData(cons);
    14130 assert(consdata != NULL);
    14131
    14132 if( consdata->lhs == lhs )
    14133 return SCIP_OKAY;
    14134
    14135 consdata->lhs = lhs;
    14136
    14137 /* not sure we care about any of these flags for original constraints */
    14138 consdata->ispropagated = FALSE;
    14139
    14140 return SCIP_OKAY;
    14141}
    14142
    14143/** changes right-hand-side of a nonlinear constraint
    14144 *
    14145 * @attention This method can only be called in the problem stage.
    14146 */
    14148 SCIP* scip, /**< SCIP data structure */
    14149 SCIP_CONS* cons, /**< constraint data */
    14150 SCIP_Real rhs /**< new right-hand-side */
    14151 )
    14152{
    14153 SCIP_CONSDATA* consdata;
    14154
    14155 assert(scip != NULL);
    14156 assert(cons != NULL);
    14157 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
    14158
    14160 {
    14161 SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
    14162 return SCIP_INVALIDCALL;
    14163 }
    14164
    14165 /* we should have an original constraint */
    14166 assert(SCIPconsIsOriginal(cons));
    14167
    14168 consdata = SCIPconsGetData(cons);
    14169 assert(consdata != NULL);
    14170
    14171 if( consdata->rhs == rhs )
    14172 return SCIP_OKAY;
    14173
    14174 consdata->rhs = rhs;
    14175
    14176 /* not sure we care about any of these flags for original constraints */
    14177 consdata->ispropagated = FALSE;
    14178
    14179 return SCIP_OKAY;
    14180}
    14181
    14182/** changes expression of a nonlinear constraint
    14183 *
    14184 * @attention This method can only be called in the problem stage.
    14185 */
    14187 SCIP* scip, /**< SCIP data structure */
    14188 SCIP_CONS* cons, /**< constraint data */
    14189 SCIP_EXPR* expr /**< new expression */
    14190 )
    14191{
    14192 SCIP_CONSHDLR* conshdlr;
    14193 SCIP_CONSDATA* consdata;
    14194
    14195 assert(scip != NULL);
    14196 assert(cons != NULL);
    14197 assert(expr != NULL);
    14198
    14200 {
    14201 SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
    14202 return SCIP_INVALIDCALL;
    14203 }
    14204
    14205 /* we should have an original constraint */
    14206 assert(SCIPconsIsOriginal(cons));
    14207
    14208 conshdlr = SCIPconsGetHdlr(cons);
    14209 assert(conshdlr != NULL);
    14210 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    14211
    14212 consdata = SCIPconsGetData(cons);
    14213 assert(consdata != NULL);
    14214 assert(consdata->expr != NULL);
    14215
    14216 /* we should not have collected additional data for the expr
    14217 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
    14218 */
    14219 assert(consdata->nvarexprs == 0);
    14220 assert(consdata->varexprs == NULL);
    14221 assert(!consdata->catchedevents);
    14222
    14223 SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
    14224
    14225 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
    14226 SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    14227
    14228 /* not sure we care about any of these flags for original constraints */
    14229 consdata->curv = SCIP_EXPRCURV_UNKNOWN;
    14230 consdata->issimplified = FALSE;
    14231 consdata->ispropagated = FALSE;
    14232
    14233 return SCIP_OKAY;
    14234}
    14235
    14236/** adds coef * var to nonlinear constraint
    14237 *
    14238 * @attention This method can only be called in the problem stage.
    14239 */
    14241 SCIP* scip, /**< SCIP data structure */
    14242 SCIP_CONS* cons, /**< constraint data */
    14243 SCIP_VAR* var, /**< variable */
    14244 SCIP_Real coef /**< coefficient */
    14245 )
    14246{
    14247 SCIP_CONSHDLR* conshdlr;
    14248 SCIP_CONSDATA* consdata;
    14249 SCIP_EXPR* varexpr;
    14250
    14251 assert(scip != NULL);
    14252 assert(cons != NULL);
    14253
    14255 {
    14256 SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
    14257 return SCIP_INVALIDCALL;
    14258 }
    14259
    14260 /* we should have an original constraint */
    14261 assert(SCIPconsIsOriginal(cons));
    14262
    14263 if( coef == 0.0 )
    14264 return SCIP_OKAY;
    14265
    14266 conshdlr = SCIPconsGetHdlr(cons);
    14267 assert(conshdlr != NULL);
    14268 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    14269
    14270 consdata = SCIPconsGetData(cons);
    14271 assert(consdata != NULL);
    14272 assert(consdata->expr != NULL);
    14273
    14274 /* we should not have collected additional data for it
    14275 * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
    14276 */
    14277 assert(consdata->nvarexprs == 0);
    14278 assert(consdata->varexprs == NULL);
    14279 assert(!consdata->catchedevents);
    14280
    14281 SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
    14282
    14283 /* append to sum, if consdata->expr is sum and not used anywhere else */
    14284 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
    14285 {
    14286 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
    14287 }
    14288 else
    14289 {
    14290 /* create new expression = 1 * consdata->expr + coef * var */
    14291 SCIP_EXPR* children[2] = { consdata->expr, varexpr };
    14292 SCIP_Real coefs[2] = { 1.0, coef };
    14293
    14294 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
    14295
    14296 /* release old root expr */
    14297 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
    14298 }
    14299
    14300 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
    14301
    14302 /* not sure we care about any of these flags for original constraints */
    14303 consdata->issimplified = FALSE;
    14304 consdata->ispropagated = FALSE;
    14305
    14306 return SCIP_OKAY;
    14307}
    14308
    14309/** adds coef * expr to nonlinear constraint
    14310 *
    14311 * @attention This method can only be called in the problem stage.
    14312 */
    14314 SCIP* scip, /**< SCIP data structure */
    14315 SCIP_CONS* cons, /**< nonlinear constraint */
    14316 SCIP_EXPR* expr, /**< expression */
    14317 SCIP_Real coef /**< coefficient */
    14318 )
    14319{
    14320 SCIP_CONSHDLR* conshdlr;
    14321 SCIP_CONSDATA* consdata;
    14322 SCIP_EXPR* exprowned;
    14323
    14324 assert(scip != NULL);
    14325 assert(cons != NULL);
    14326
    14328 {
    14329 SCIPerrorMessage("SCIPaddExprNonlinear can only be called in problem stage.\n");
    14330 return SCIP_INVALIDCALL;
    14331 }
    14332
    14333 /* we should have an original constraint */
    14334 assert(SCIPconsIsOriginal(cons));
    14335
    14336 if( coef == 0.0 )
    14337 return SCIP_OKAY;
    14338
    14339 conshdlr = SCIPconsGetHdlr(cons);
    14340 assert(conshdlr != NULL);
    14341 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
    14342
    14343 consdata = SCIPconsGetData(cons);
    14344 assert(consdata != NULL);
    14345 assert(consdata->expr != NULL);
    14346
    14347 /* free quadratic representation, if any is stored */
    14348 SCIPfreeExprQuadratic(scip, consdata->expr);
    14349
    14350 /* free varexprs in consdata, in case they have been stored
    14351 * (e.g., by a call to consGet(N)VarsNonlinear)
    14352 */
    14353 SCIP_CALL( freeVarExprs(scip, consdata) );
    14354
    14355 /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
    14356 SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
    14357
    14358 /* append to sum, if consdata->expr is sum and not used anywhere else */
    14359 if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
    14360 {
    14361 SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
    14362 }
    14363 else
    14364 {
    14365 /* create new expression = 1 * consdata->expr + coef * var */
    14366 SCIP_EXPR* children[2] = { consdata->expr, exprowned };
    14367 SCIP_Real coefs[2] = { 1.0, coef };
    14368
    14369 SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
    14370
    14371 /* release old root expr */
    14372 SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
    14373 }
    14374
    14375 SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
    14376
    14377 /* not sure we care about any of these flags for original constraints */
    14378 consdata->issimplified = FALSE;
    14379 consdata->ispropagated = FALSE;
    14380
    14381 return SCIP_OKAY;
    14382}
    14383
    14384/** computes value of constraint expression in a given solution
    14385 *
    14386 * Stores value of constraint expression in sol in activity.
    14387 * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
    14388 */
    14390 SCIP* scip, /**< SCIP data structure */
    14391 SCIP_CONS* cons, /**< constraint */
    14392 SCIP_SOL* sol, /**< solution */
    14393 SCIP_Real* activity /**< buffer to store computed activity */
    14394 )
    14395{
    14396 SCIP_CONSDATA* consdata;
    14397
    14398 assert(cons != NULL);
    14399 assert(activity != NULL);
    14400
    14401 consdata = SCIPconsGetData(cons);
    14402 assert(consdata != NULL);
    14403
    14404 SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
    14405 *activity = SCIPexprGetEvalValue(consdata->expr);
    14406
    14407 return SCIP_OKAY;
    14408}
    14409
    14410/** gets absolute violation of nonlinear constraint
    14411 *
    14412 * This function evaluates the constraints in the given solution.
    14413 *
    14414 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
    14415 */
    14417 SCIP* scip, /**< SCIP data structure */
    14418 SCIP_CONS* cons, /**< constraint */
    14419 SCIP_SOL* sol, /**< solution to check */
    14420 SCIP_Real* viol /**< buffer to store computed violation */
    14421 )
    14422{
    14423 assert(cons != NULL);
    14424 assert(viol != NULL);
    14425
    14426 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
    14427 *viol = getConsAbsViolation(cons);
    14428
    14429 return SCIP_OKAY;
    14430}
    14431
    14432/** gets scaled violation of nonlinear constraint
    14433 *
    14434 * This function evaluates the constraints in the given solution.
    14435 *
    14436 * The scaling that is applied to the absolute violation of the constraint
    14437 * depends on the setting of parameter constraints/nonlinear/violscale.
    14438 */
    14440 SCIP* scip, /**< SCIP data structure */
    14441 SCIP_CONS* cons, /**< constraint */
    14442 SCIP_SOL* sol, /**< solution to check */
    14443 SCIP_Real* viol /**< buffer to store computed violation */
    14444 )
    14445{
    14446 assert(cons != NULL);
    14447 assert(viol != NULL);
    14448
    14449 SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
    14450 SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
    14451
    14452 return SCIP_OKAY;
    14453}
    14454
    14455/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
    14457 SCIP* scip, /**< SCIP data structure */
    14458 SCIP_CONS* cons, /**< nonlinear constraint */
    14459 SCIP_VAR** var, /**< pointer to store the variable */
    14460 SCIP_Real* coef /**< pointer to store the coefficient */
    14461 )
    14462{
    14463 SCIP_CONSDATA* consdata;
    14464
    14465 assert(cons != NULL);
    14466 assert(var != NULL);
    14467 assert(coef != NULL);
    14468
    14469 /* check for a linear variable that can be increased or decreased without harming feasibility */
    14471
    14472 consdata = SCIPconsGetData(cons);
    14473 assert(consdata != NULL);
    14474
    14475 *var = consdata->linvardecr;
    14476 *coef = consdata->linvardecrcoef;
    14477}
    14478
    14479/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
    14481 SCIP* scip, /**< SCIP data structure */
    14482 SCIP_CONS* cons, /**< nonlinear constraint */
    14483 SCIP_VAR** var, /**< pointer to store the variable */
    14484 SCIP_Real* coef /**< pointer to store the coefficient */
    14485 )
    14486{
    14487 SCIP_CONSDATA* consdata;
    14488
    14489 assert(cons != NULL);
    14490 assert(var != NULL);
    14491 assert(coef != NULL);
    14492
    14493 /* check for a linear variable that can be increased or decreased without harming feasibility */
    14495
    14496 consdata = SCIPconsGetData(cons);
    14497 assert(consdata != NULL);
    14498
    14499 *var = consdata->linvarincr;
    14500 *coef = consdata->linvarincrcoef;
    14501}
    14502
    14503
    14504/*
    14505 * Methods for Expressions in Nonlinear Constraints
    14506 */
    14507
    14508/** returns the number of positive rounding locks of an expression */
    14510 SCIP_EXPR* expr /**< expression */
    14511 )
    14512{
    14513 assert(expr != NULL);
    14514 assert(SCIPexprGetOwnerData(expr) != NULL);
    14515
    14516 return SCIPexprGetOwnerData(expr)->nlockspos;
    14517}
    14518
    14519/** returns the number of negative rounding locks of an expression */
    14521 SCIP_EXPR* expr /**< expression */
    14522 )
    14523{
    14524 assert(expr != NULL);
    14525 assert(SCIPexprGetOwnerData(expr) != NULL);
    14526
    14527 return SCIPexprGetOwnerData(expr)->nlocksneg;
    14528}
    14529
    14530/** returns the variable used for linearizing a given expression (return value might be NULL)
    14531 *
    14532 * @note for variable expression it returns the corresponding variable
    14533 */
    14535 SCIP_EXPR* expr /**< expression */
    14536 )
    14537{
    14538 SCIP_EXPR_OWNERDATA* ownerdata;
    14539
    14540 assert(expr != NULL);
    14541
    14542 ownerdata = SCIPexprGetOwnerData(expr);
    14543 assert(ownerdata != NULL);
    14544
    14545 return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
    14546}
    14547
    14548/** returns the number of enforcements for an expression */
    14550 SCIP_EXPR* expr /**< expression */
    14551 )
    14552{
    14553 assert(expr != NULL);
    14554 assert(SCIPexprGetOwnerData(expr) != NULL);
    14555
    14556 return SCIPexprGetOwnerData(expr)->nenfos;
    14557}
    14558
    14559/** returns the data for one of the enforcements of an expression */
    14561 SCIP_EXPR* expr, /**< expression */
    14562 int idx, /**< position of enforcement in enfos array */
    14563 SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
    14564 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
    14565 SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
    14566 SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
    14567 SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
    14568 SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
    14569 )
    14570{
    14571 SCIP_EXPR_OWNERDATA* ownerdata;
    14572
    14573 assert(expr != NULL);
    14574
    14575 ownerdata = SCIPexprGetOwnerData(expr);
    14576 assert(ownerdata != NULL);
    14577 assert(idx >= 0);
    14578 assert(idx < ownerdata->nenfos);
    14579 assert(ownerdata->enfos[idx] != NULL);
    14580 assert(nlhdlr != NULL);
    14581
    14582 *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
    14583
    14584 if( nlhdlrexprdata != NULL )
    14585 *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
    14586
    14587 if( nlhdlrparticipation != NULL )
    14588 *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
    14589
    14590 if( sepabelowusesactivity != NULL )
    14591 *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
    14592
    14593 if( sepaaboveusesactivity != NULL )
    14594 *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
    14595
    14596 if( auxvalue != NULL )
    14597 *auxvalue = ownerdata->enfos[idx]->auxvalue;
    14598}
    14599
    14600/** sets the auxiliary value of expression for one of the enforcements of an expression */
    14602 SCIP_EXPR* expr, /**< expression */
    14603 int idx, /**< position of enforcement in enfos array */
    14604 SCIP_Real auxvalue /**< the new value of auxval */
    14605 )
    14606{
    14607 SCIP_EXPR_OWNERDATA* ownerdata;
    14608
    14609 assert(expr != NULL);
    14610
    14611 ownerdata = SCIPexprGetOwnerData(expr);
    14612 assert(ownerdata != NULL);
    14613
    14614 assert(idx >= 0);
    14615 assert(idx < ownerdata->nenfos);
    14616 assert(ownerdata->enfos[idx] != NULL);
    14617
    14618 ownerdata->enfos[idx]->auxvalue = auxvalue;
    14619}
    14620
    14621/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
    14622 *
    14623 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
    14624 */
    14626 SCIP_EXPR* expr /**< expression */
    14627 )
    14628{
    14629 assert(expr != NULL);
    14630 assert(SCIPexprGetOwnerData(expr) != NULL);
    14631
    14632 return SCIPexprGetOwnerData(expr)->nactivityusesprop;
    14633}
    14634
    14635/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
    14636 *
    14637 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
    14638 */
    14640 SCIP_EXPR* expr /**< expression */
    14641 )
    14642{
    14643 assert(expr != NULL);
    14644 assert(SCIPexprGetOwnerData(expr) != NULL);
    14645
    14646 return SCIPexprGetOwnerData(expr)->nactivityusessepa;
    14647}
    14648
    14649/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
    14650 *
    14651 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
    14652 */
    14654 SCIP_EXPR* expr /**< expression */
    14655 )
    14656{
    14657 assert(expr != NULL);
    14658 assert(SCIPexprGetOwnerData(expr) != NULL);
    14659
    14660 return SCIPexprGetOwnerData(expr)->nauxvaruses;
    14661}
    14662
    14663/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
    14664 *
    14665 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
    14666 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
    14667 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
    14668 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
    14669 * and also increments this count for all variables in the expression.
    14670 *
    14671 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
    14672 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
    14673 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
    14674 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
    14675 */
    14677 SCIP* scip, /**< SCIP data structure */
    14678 SCIP_EXPR* expr, /**< expression */
    14679 SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
    14680 SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
    14681 SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
    14682 SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
    14683 )
    14684{
    14685 SCIP_EXPR_OWNERDATA* ownerdata;
    14686
    14687 assert(expr != NULL);
    14688
    14689 ownerdata = SCIPexprGetOwnerData(expr);
    14690 assert(ownerdata != NULL);
    14691
    14692 /* do not store auxvar request for variable expressions */
    14693 if( useauxvar && SCIPisExprVar(scip, expr) )
    14694 useauxvar = FALSE;
    14695
    14696 if( ownerdata->nenfos >= 0 &&
    14697 ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
    14698 (ownerdata->nauxvaruses == 0 && useauxvar)
    14699 ) )
    14700 {
    14701 /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
    14702 * we require additional enforcement methods, that is,
    14703 * - activity of expr was not used before but will be used now, or
    14704 * - auxiliary variable of expr was not required before but will be used now
    14705 */
    14706 SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
    14707 }
    14708
    14709 if( useauxvar )
    14710 ++ownerdata->nauxvaruses;
    14711
    14712 if( useactivityforprop )
    14713 ++ownerdata->nactivityusesprop;
    14714
    14715 if( useactivityforsepabelow || useactivityforsepaabove )
    14716 ++ownerdata->nactivityusessepa;
    14717
    14718 /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
    14719 * information is used in detectNlhdlr()
    14720 */
    14721 if( useactivityforsepabelow )
    14722 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
    14723 if( useactivityforsepaabove )
    14724 SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
    14725
    14726 if( useactivityforprop )
    14727 {
    14728 /* if activity will be used for propagation, then make sure there is a valid activity
    14729 * this way, we can do a reversepropcall after detectNlhdlr
    14730 */
    14732 }
    14733
    14734 /* increase the nactivityusedsepa counter for all variables used in the given expression */
    14735 if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
    14736 {
    14737 SCIP_EXPRITER* it;
    14738
    14739 /* create and initialize iterator */
    14742
    14743 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    14744 if( SCIPisExprVar(scip, expr) )
    14745 ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
    14746
    14747 /* free iterator */
    14748 SCIPfreeExpriter(&it);
    14749 }
    14750
    14751 return SCIP_OKAY;
    14752}
    14753
    14754/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
    14755 *
    14756 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
    14757 * Assume that f(x) is associated with auxiliary variable z.
    14758 *
    14759 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
    14760 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
    14761 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
    14762 *
    14763 * If necessary, f is evaluated in the given solution. If that fails (domain error),
    14764 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
    14765 */
    14767 SCIP* scip, /**< SCIP data structure */
    14768 SCIP_EXPR* expr, /**< expression */
    14769 SCIP_SOL* sol, /**< solution */
    14770 SCIP_Longint soltag, /**< tag of solution */
    14771 SCIP_Real* viol, /**< buffer to store computed violation */
    14772 SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
    14773 SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
    14774 )
    14775{
    14776 assert(scip != NULL);
    14777 assert(expr != NULL);
    14778 assert(viol != NULL);
    14779
    14780 /* make sure expression has been evaluated */
    14781 SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
    14782
    14783 /* get violation from internal method */
    14784 *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
    14785
    14786 return SCIP_OKAY;
    14787}
    14788
    14789/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
    14790 *
    14791 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
    14792 * Assume that f(w) is associated with auxiliary variable z.
    14793 *
    14794 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
    14795 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
    14796 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
    14797 *
    14798 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
    14799 * both `violover` and `violunder` are set to TRUE.
    14800 */
    14802 SCIP* scip, /**< SCIP data structure */
    14803 SCIP_EXPR* expr, /**< expression */
    14804 SCIP_Real auxvalue, /**< the value of f(w) */
    14805 SCIP_SOL* sol, /**< solution that has been evaluated */
    14806 SCIP_Real* viol, /**< buffer to store computed violation */
    14807 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
    14808 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
    14809 )
    14810{
    14811 assert(scip != NULL);
    14812 assert(expr != NULL);
    14813 assert(viol != NULL);
    14814
    14815 /* get violation from internal method */
    14816 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
    14817
    14818 return SCIP_OKAY;
    14819}
    14820
    14821
    14822/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
    14823 *
    14824 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
    14825 * Assume that f(w) is associated with auxiliary variable z.
    14826 *
    14827 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
    14828 * the absolute violation divided by max(1,|f(w)|).
    14829 *
    14830 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
    14831 * both `violover` and `violunder` are set to TRUE.
    14832 */
    14834 SCIP* scip, /**< SCIP data structure */
    14835 SCIP_EXPR* expr, /**< expression */
    14836 SCIP_Real auxvalue, /**< the value of f(w) */
    14837 SCIP_SOL* sol, /**< solution that has been evaluated */
    14838 SCIP_Real* viol, /**< buffer to store computed violation */
    14839 SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
    14840 SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
    14841 )
    14842{
    14843 assert(scip != NULL);
    14844 assert(expr != NULL);
    14845 assert(viol != NULL);
    14846
    14847 /* get violation from internal method */
    14848 *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
    14849
    14850 if( !SCIPisInfinity(scip, *viol) )
    14851 {
    14852 assert(auxvalue != SCIP_INVALID);
    14853 /* TODO maybe we should rather use max(eps,|auxvalue|)? */
    14854 *viol /= MAX(1.0, REALABS(auxvalue));
    14855 }
    14856
    14857 return SCIP_OKAY;
    14858}
    14859
    14860/** returns bounds on the expression
    14861 *
    14862 * This gives an intersection of bounds from
    14863 * - activity calculation (SCIPexprGetActivity()), if valid,
    14864 * - auxiliary variable, if present,
    14865 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
    14866 *
    14867 * @note The returned interval can be empty!
    14868 */
    14870 SCIP* scip, /**< SCIP data structure */
    14871 SCIP_EXPR* expr /**< expression */
    14872 )
    14873{
    14874 SCIP_EXPR_OWNERDATA* ownerdata;
    14875 SCIP_CONSHDLRDATA* conshdlrdata;
    14876 SCIP_INTERVAL bounds;
    14877
    14878 assert(scip != NULL);
    14879 assert(expr != NULL);
    14880
    14881 ownerdata = SCIPexprGetOwnerData(expr);
    14882 assert(ownerdata != NULL);
    14883
    14884 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    14885 assert(conshdlrdata != NULL);
    14886
    14887 /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
    14888
    14889 /* start with propbounds if they belong to current propagation */
    14890 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
    14891 {
    14892 bounds = ownerdata->propbounds;
    14893 /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
    14894 }
    14895 else
    14897
    14898 if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
    14899 {
    14900 /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
    14901 /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
    14903 }
    14904
    14905 if( ownerdata->auxvar != NULL )
    14906 {
    14907 /* apply auxiliary variable bounds to bounds */
    14908 SCIP_INTERVAL auxvarbounds;
    14909
    14910 auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
    14911 /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
    14912 SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
    14913 }
    14914
    14915 /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
    14916
    14917 return bounds;
    14918}
    14919
    14920/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
    14921 * corresponding (auxiliary) variable (if any)
    14922 *
    14923 * @attention this function should only be called during domain propagation in cons_nonlinear
    14924 */
    14926 SCIP* scip, /**< SCIP data structure */
    14927 SCIP_EXPR* expr, /**< expression to be tightened */
    14928 SCIP_INTERVAL newbounds, /**< new bounds for the expression */
    14929 SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
    14930 int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
    14931 )
    14932{
    14933 SCIP_EXPR_OWNERDATA* ownerdata;
    14934 SCIP_CONSHDLRDATA* conshdlrdata;
    14935
    14936 assert(scip != NULL);
    14937 assert(expr != NULL);
    14938 assert(cutoff != NULL);
    14939
    14940 ownerdata = SCIPexprGetOwnerData(expr);
    14941 assert(ownerdata != NULL);
    14942 assert(ownerdata->conshdlr != NULL);
    14943
    14944 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    14945 assert(conshdlrdata != NULL);
    14946
    14947 /* the code below assumes that current activity is valid
    14948 * if it turns out that we cannot ensure that, then we should change code
    14949 */
    14950 assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
    14952
    14953 *cutoff = FALSE;
    14954
    14955#ifdef DEBUG_PROP
    14956 SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
    14957 SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
    14958 SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
    14959#endif
    14960
    14961 if( SCIPexprIsIntegral(expr) )
    14962 {
    14963 /* apply integrality to new bounds
    14964 * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
    14965 */
    14966 if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
    14967 newbounds.inf = SCIPceil(scip, newbounds.inf);
    14968 if( newbounds.sup < SCIP_INTERVAL_INFINITY )
    14969 newbounds.sup = SCIPfloor(scip, newbounds.sup);
    14970#ifdef DEBUG_PROP
    14971 SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
    14972#endif
    14973 }
    14974
    14976 {
    14977 SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
    14978
    14979 *cutoff = TRUE;
    14980 return SCIP_OKAY;
    14981 }
    14982
    14983 /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
    14984 if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
    14985 {
    14986 SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
    14987
    14988 *cutoff = TRUE;
    14989 return SCIP_OKAY;
    14990 }
    14991
    14992 /* tighten newbounds w.r.t. existing expr->propbounds or activity */
    14993 if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
    14994 {
    14995 /* if already having propbounds in expr, then tighten newbounds by propbounds */
    14996 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
    14997 }
    14998 else
    14999 {
    15000 /* first time we have propbounds for expr in this propagation rounds:
    15001 * intersect with activity (though don't let it become empty if very close intervals)
    15002 */
    15003 SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
    15004 }
    15005#ifdef DEBUG_PROP
    15006 SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
    15007#endif
    15008
    15009 /* check if the new bounds lead to an empty interval */
    15011 {
    15012 SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
    15013
    15014 *cutoff = TRUE;
    15015 return SCIP_OKAY;
    15016 }
    15017
    15018 /* if expr is not constant or variable, then store newbounds in expr->propbounds
    15019 * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
    15020 * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
    15021 */
    15022 if( SCIPexprGetNChildren(expr) > 0 )
    15023 {
    15024 ownerdata->propbounds = newbounds;
    15025 ownerdata->propboundstag = conshdlrdata->curpropboundstag;
    15026 }
    15027
    15028 /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
    15029 * propagation or update of auxvar bounds
    15030 * TODO? if we first had a considerable tightening and then only get small tightenings under the same
    15031 * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
    15032 * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
    15033 * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
    15034 * one or should we not even update propbounds to newbounds if the update is small?
    15035 */
    15036 if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
    15037 {
    15038#ifdef DEBUG_PROP
    15039 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);
    15040#endif
    15041 return SCIP_OKAY;
    15042 }
    15043
    15044 if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
    15045 {
    15046 /* add expression to propagation queue if not there yet and not var or constant and
    15047 * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
    15048 */
    15049#ifdef DEBUG_PROP
    15050 SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
    15051#endif
    15052 SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
    15053 ownerdata->inpropqueue = TRUE;
    15054 }
    15055
    15056 /* update bounds on variable or auxiliary variable */
    15057 SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
    15058
    15059 return SCIP_OKAY;
    15060}
    15061
    15062/** mark constraints that include this expression to be propagated again
    15063 *
    15064 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
    15065 * a change of variable bounds, e.g., because new information on the expression is available
    15066 * that could potentially lead to tighter expression activity values.
    15067 *
    15068 * Note, that this call marks also constraints for propagation which only share some variable
    15069 * with this expression.
    15070 */
    15072 SCIP* scip, /**< SCIP data structure */
    15073 SCIP_EXPR* expr /**< expression to propagate again */
    15074 )
    15075{
    15076 SCIP_EXPRITER* it;
    15077 SCIP_CONSDATA* consdata;
    15078 SCIP_EXPR_OWNERDATA* ownerdata;
    15079 int c;
    15080
    15081 assert(scip != NULL);
    15082 assert(expr != NULL);
    15083
    15084 ownerdata = SCIPexprGetOwnerData(expr);
    15085 assert(ownerdata != NULL);
    15086
    15087 SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
    15088
    15091
    15092 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
    15093 {
    15094 if( !SCIPisExprVar(scip, expr) )
    15095 continue;
    15096
    15097 ownerdata = SCIPexprGetOwnerData(expr);
    15098 assert(ownerdata != NULL);
    15099
    15100 for( c = 0; c < ownerdata->nconss; ++c )
    15101 {
    15102 consdata = SCIPconsGetData(ownerdata->conss[c]);
    15103 assert(consdata != NULL);
    15104 consdata->ispropagated = FALSE;
    15105 }
    15106 }
    15107
    15108 SCIPfreeExpriter(&it);
    15109
    15110 return SCIP_OKAY;
    15111}
    15112
    15113/** adds violation-branching score to an expression
    15114 *
    15115 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
    15116 * The expression must either be a variable expression or have an aux-variable.
    15117 * In the latter case, branching on auxiliary variables must have been enabled.
    15118 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
    15119 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
    15120 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
    15121 *
    15122 * @see SCIPaddExprsViolScoreNonlinear()
    15123 */
    15125 SCIP* scip, /**< SCIP data structure */
    15126 SCIP_EXPR* expr, /**< expression where to add branching score */
    15127 SCIP_Real violscore /**< violation score to add to expression */
    15128 )
    15129{
    15130 SCIP_EXPR_OWNERDATA* ownerdata;
    15131 SCIP_CONSHDLRDATA* conshdlrdata;
    15132
    15133 assert(scip != NULL);
    15134 assert(expr != NULL);
    15135 assert(violscore >= 0.0);
    15136
    15137 ownerdata = SCIPexprGetOwnerData(expr);
    15138 assert(ownerdata != NULL);
    15139
    15140 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15141 assert(conshdlrdata != NULL);
    15142
    15143 /* if not allowing to branch on auxvars, then expr must be a var-expr */
    15144 assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
    15145 /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
    15146 assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
    15147
    15148 /* reset branching score if we are in a different enfo round */
    15149 if( ownerdata->violscoretag != conshdlrdata->enforound )
    15150 {
    15151 ownerdata->violscoresum = violscore;
    15152 ownerdata->violscoremax = violscore;
    15153 ownerdata->nviolscores = 1;
    15154 ownerdata->violscoretag = conshdlrdata->enforound;
    15155 return;
    15156 }
    15157
    15158 ownerdata->violscoresum += violscore;
    15159 if( violscore > ownerdata->violscoremax )
    15160 ownerdata->violscoremax = violscore;
    15161 ++ownerdata->nviolscores;
    15162}
    15163
    15164/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
    15165 *
    15166 * Each expression must either be a variable expression or have an aux-variable.
    15167 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
    15168 * variables present in `exprs`.
    15169 */
    15171 SCIP* scip, /**< SCIP data structure */
    15172 SCIP_EXPR** exprs, /**< expressions where to add branching score */
    15173 int nexprs, /**< number of expressions */
    15174 SCIP_Real violscore, /**< violation score to add to expression */
    15175 SCIP_SOL* sol, /**< current solution */
    15176 SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
    15177 )
    15178{
    15179 SCIP_EXPRITER* it;
    15180 SCIP_EXPR** varexprs;
    15181 SCIP_EXPR* e;
    15182 int nvars;
    15183 int varssize;
    15184 int i;
    15185
    15186 assert(exprs != NULL || nexprs == 0);
    15187 assert(success != NULL);
    15188
    15189 if( nexprs == 0 )
    15190 {
    15191 *success = FALSE;
    15192 return SCIP_OKAY;
    15193 }
    15194
    15195 /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
    15196 if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
    15197 {
    15198 addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
    15199 return SCIP_OKAY;
    15200 }
    15201
    15202 /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
    15203 nvars = 0;
    15204 varssize = 5;
    15205 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
    15206
    15209
    15210 for( i = 0; i < nexprs; ++i )
    15211 {
    15212 for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
    15213 {
    15214 assert(e != NULL);
    15215
    15216 if( SCIPisExprVar(scip, e) )
    15217 {
    15218 /* add variable expression to vars array */
    15219 if( varssize == nvars )
    15220 {
    15221 varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
    15222 SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
    15223 }
    15224 assert(varssize > nvars);
    15225
    15226 varexprs[nvars++] = e;
    15227 }
    15228 }
    15229 }
    15230
    15231 SCIPfreeExpriter(&it);
    15232
    15233 addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
    15234
    15235 SCIPfreeBufferArray(scip, &varexprs);
    15236
    15237 return SCIP_OKAY;
    15238}
    15239
    15240/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
    15242 SCIP_EXPR* expr /**< expression */
    15243 )
    15244{
    15245 SCIP_EXPR_OWNERDATA* ownerdata;
    15246 SCIP_CONSHDLRDATA* conshdlrdata;
    15247
    15248 assert(expr != NULL);
    15249
    15250 ownerdata = SCIPexprGetOwnerData(expr);
    15251 assert(ownerdata != NULL);
    15252
    15253 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15254 assert(conshdlrdata != NULL);
    15255
    15256 if( conshdlrdata->enforound != ownerdata->violscoretag )
    15257 return 0.0;
    15258
    15259 if( ownerdata->nviolscores == 0 )
    15260 return 0.0;
    15261
    15262 switch( conshdlrdata->branchscoreagg )
    15263 {
    15264 case 'a' :
    15265 /* average */
    15266 return ownerdata->violscoresum / ownerdata->nviolscores;
    15267
    15268 case 'm' :
    15269 /* maximum */
    15270 return ownerdata->violscoremax;
    15271
    15272 case 's' :
    15273 /* sum */
    15274 return ownerdata->violscoresum;
    15275
    15276 default:
    15277 SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
    15278 SCIPABORT();
    15279 return SCIP_INVALID;
    15280 }
    15281}
    15282
    15283/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
    15284 *
    15285 * @see SCIPexprGetDerivative()
    15286 */
    15288 SCIP* scip, /**< SCIP data structure */
    15289 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
    15290 SCIP_VAR* var /**< variable (needs to be in the expression) */
    15291 )
    15292{
    15293 SCIP_EXPR_OWNERDATA* ownerdata;
    15294 SCIP_CONSHDLRDATA* conshdlrdata;
    15295 SCIP_EXPR* varexpr;
    15296
    15297 assert(scip != NULL);
    15298 assert(expr != NULL);
    15299 assert(var != NULL);
    15300
    15301 /* return 0.0 for value expression */
    15302 if( SCIPisExprValue(scip, expr) )
    15303 {
    15304 assert(SCIPexprGetDerivative(expr) == 0.0);
    15305 return 0.0;
    15306 }
    15307
    15308 /* check if an error occurred during the last SCIPevalExprGradient() call */
    15309 if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
    15310 return SCIP_INVALID;
    15311
    15312 ownerdata = SCIPexprGetOwnerData(expr);
    15313 assert(ownerdata != NULL);
    15314
    15315 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15316 assert(conshdlrdata != NULL);
    15317
    15318 /* use variable to expressions mapping which is stored in the constraint handler data */
    15319 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
    15320
    15321 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
    15322 assert(varexpr != NULL);
    15323 assert(SCIPisExprVar(scip, varexpr));
    15324
    15325 /* use difftag to decide whether the variable belongs to the expression */
    15326 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
    15327}
    15328
    15329/** 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)
    15330 *
    15331 * @see SCIPexprGetBardot()
    15332 */
    15334 SCIP* scip, /**< SCIP data structure */
    15335 SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
    15336 SCIP_VAR* var /**< variable (needs to be in the expression) */
    15337 )
    15338{
    15339 SCIP_EXPR_OWNERDATA* ownerdata;
    15340 SCIP_CONSHDLRDATA* conshdlrdata;
    15341 SCIP_EXPR* varexpr;
    15342
    15343 assert(scip != NULL);
    15344 assert(expr != NULL);
    15345 assert(var != NULL);
    15346
    15347 /* return 0.0 for value expression */
    15348 if( SCIPisExprValue(scip, expr) )
    15349 return 0.0;
    15350
    15351 /* check if an error occurred during the last SCIPevalExprHessianDir() call */
    15352 if( SCIPexprGetBardot(expr) == SCIP_INVALID )
    15353 return SCIP_INVALID;
    15354
    15355 ownerdata = SCIPexprGetOwnerData(expr);
    15356 assert(ownerdata != NULL);
    15357
    15358 conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
    15359 assert(conshdlrdata != NULL);
    15360
    15361 /* use variable to expressions mapping which is stored in the constraint handler data;
    15362 * if this fails it means that we are asking for the var's component of H*u for a var
    15363 * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
    15364 */
    15365 assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
    15366
    15367 varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
    15368 assert(varexpr != NULL);
    15369 assert(SCIPisExprVar(scip, varexpr));
    15370
    15371 /* use difftag to decide whether the variable belongs to the expression */
    15372 return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
    15373}
    15374
    15375/** evaluates quadratic term in a solution w.r.t. auxiliary variables
    15376 *
    15377 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
    15378 */
    15380 SCIP* scip, /**< SCIP data structure */
    15381 SCIP_EXPR* expr, /**< quadratic expression */
    15382 SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
    15383 )
    15384{
    15385 SCIP_Real auxvalue;
    15386 int nlinexprs;
    15387 SCIP_Real* lincoefs;
    15388 SCIP_EXPR** linexprs;
    15389 int nquadexprs;
    15390 int nbilinexprs;
    15391 int i;
    15392
    15393 assert(scip != NULL);
    15394 assert(expr != NULL);
    15395
    15396 SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
    15397
    15398 /* linear terms */
    15399 for( i = 0; i < nlinexprs; ++i )
    15400 {
    15401 assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
    15402 auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
    15403 }
    15404
    15405 /* quadratic terms */
    15406 for( i = 0; i < nquadexprs; ++i )
    15407 {
    15408 SCIP_EXPR* quadexprterm;
    15409 SCIP_Real lincoef;
    15410 SCIP_Real sqrcoef;
    15411 SCIP_Real solval;
    15412
    15413 SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
    15414
    15415 assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
    15416
    15417 solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
    15418 auxvalue += (lincoef + sqrcoef * solval) * solval;
    15419 }
    15420
    15421 /* bilinear terms */
    15422 for( i = 0; i < nbilinexprs; ++i )
    15423 {
    15424 SCIP_EXPR* expr1;
    15425 SCIP_EXPR* expr2;
    15426 SCIP_Real coef;
    15427
    15428 SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
    15429
    15430 assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
    15431 assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
    15432 auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
    15433 }
    15434
    15435 return auxvalue;
    15436}
    15437
    15438/**@addtogroup PublicNlhdlrInterfaceMethods
    15439 * @{
    15440 */
    15441
    15442/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
    15444 SCIP* scip, /**< SCIP data structure */
    15445 SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
    15446 const char* name, /**< name of nonlinear handler (must not be NULL) */
    15447 const char* desc, /**< description of nonlinear handler (can be NULL) */
    15448 int detectpriority, /**< detection priority of nonlinear handler */
    15449 int enfopriority, /**< enforcement priority of nonlinear handler */
    15450 SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
    15451 SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
    15452 SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
    15453 )
    15454{
    15455 SCIP_CONSHDLR* conshdlr;
    15456 SCIP_CONSHDLRDATA* conshdlrdata;
    15457
    15458 assert(scip != NULL);
    15459 assert(nlhdlr != NULL);
    15460 assert(detect != NULL);
    15461
    15462 /* find myself */
    15463 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
    15464 if( conshdlr == NULL )
    15465 {
    15466 SCIPerrorMessage("nonlinear constraint handler not found");
    15467 return SCIP_PLUGINNOTFOUND;
    15468 }
    15469
    15470 /* create nlhdlr */
    15471 SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
    15472
    15473 /* include into constraint handler */
    15474 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15475 assert(conshdlrdata != NULL);
    15476
    15477 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
    15478
    15479 conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
    15480 ++conshdlrdata->nnlhdlrs;
    15481
    15482 /* sort nonlinear handlers by detection priority, in decreasing order
    15483 * will happen in INIT, so only do when called late
    15484 */
    15485 if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
    15486 SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
    15487
    15488 return SCIP_OKAY;
    15489}
    15490
    15491/** get number of nonlinear handler */
    15493 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    15494 )
    15495{
    15496 SCIP_CONSHDLRDATA* conshdlrdata;
    15497
    15498 assert(conshdlr != NULL);
    15499
    15500 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15501 assert(conshdlrdata != NULL);
    15502
    15503 return conshdlrdata->nnlhdlrs;
    15504}
    15505
    15506/** get nonlinear handlers */
    15508 SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
    15509 )
    15510{
    15511 SCIP_CONSHDLRDATA* conshdlrdata;
    15512
    15513 assert(conshdlr != NULL);
    15514
    15515 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15516 assert(conshdlrdata != NULL);
    15517
    15518 return conshdlrdata->nlhdlrs;
    15519}
    15520
    15521/** returns a nonlinear handler of a given name (or NULL if not found) */
    15523 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    15524 const char* name /**< name of nonlinear handler */
    15525 )
    15526{
    15527 SCIP_CONSHDLRDATA* conshdlrdata;
    15528 int h;
    15529
    15530 assert(conshdlr != NULL);
    15531 assert(name != NULL);
    15532
    15533 conshdlrdata = SCIPconshdlrGetData(conshdlr);
    15534 assert(conshdlrdata != NULL);
    15535
    15536 for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
    15537 if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
    15538 return conshdlrdata->nlhdlrs[h];
    15539
    15540 return NULL;
    15541}
    15542
    15543/** gives expression data that a given nonlinear handler stored in an expression
    15544 *
    15545 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
    15546 */
    15548 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
    15549 SCIP_EXPR* expr /**< expression */
    15550 )
    15551{
    15552 SCIP_EXPR_OWNERDATA* ownerdata;
    15553 int e;
    15554
    15555 assert(nlhdlr != NULL);
    15556 assert(expr != NULL);
    15557
    15558 ownerdata = SCIPexprGetOwnerData(expr);
    15559 assert(ownerdata != NULL);
    15560
    15561 for( e = 0; e < ownerdata->nenfos; ++e )
    15562 if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
    15563 return ownerdata->enfos[e]->nlhdlrexprdata;
    15564
    15565 return NULL;
    15566}
    15567
    15568/** @} */
    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 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:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_Longint
    Definition: def.h:141
    #define EPSROUND(x, eps)
    Definition: def.h:193
    #define EPSISINT(x, eps)
    Definition: def.h:195
    #define SCIP_REAL_MAX
    Definition: def.h:158
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_INTERVAL_INFINITY
    Definition: def.h:180
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define MAX3(x, y, z)
    Definition: def.h:228
    #define SCIP_Real
    Definition: def.h:156
    #define ABS(x)
    Definition: def.h:216
    #define EPSFRAC(x, eps)
    Definition: def.h:194
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:334
    #define SCIP_LONGINT_FORMAT
    Definition: def.h:148
    #define SCIPABORT()
    Definition: def.h:327
    #define REALABS(x)
    Definition: def.h:182
    #define SCIP_CALL(x)
    Definition: def.h:355
    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)
    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)
    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:4346
    int SCIPconshdlrGetMaxNActiveConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:5112
    int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4778
    const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4316
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4336
    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:4735
    SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
    Definition: cons.c:8419
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8648
    SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
    Definition: cons.c:8409
    SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
    Definition: cons.c:8507
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8558
    SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
    Definition: scip_cons.c:2536
    SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
    Definition: cons.c:8688
    SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
    Definition: cons.c:8588
    SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
    Definition: cons.c:8518
    SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
    Definition: cons.c:8698
    SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
    Definition: cons.c:8578
    SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
    Definition: cons.c:8450
    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:8608
    SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
    Definition: cons.c:8628
    SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
    Definition: cons.c:8486
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8389
    SCIP_Bool SCIPconsIsSeparationEnabled(SCIP_CONS *cons)
    Definition: cons.c:8496
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8638
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8568
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8658
    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:8483
    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:4130
    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:4259
    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
    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:23683
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23478
    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:23386
    int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
    Definition: var.c:4386
    SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23498
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_Bool SCIPvarIsNonimpliedIntegral(SCIP_VAR *var)
    Definition: var.c:23506
    SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
    Definition: var.c:23900
    void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
    Definition: var.c:23618
    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:23453
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24142
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23652
    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:23267
    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:23490
    SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
    Definition: scip_var.c:10113
    int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24642
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
    Definition: var.c:24653
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24120
    SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:11057
    SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR *var)
    Definition: var.c:23463
    int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
    Definition: var.c:17274
    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:919
    #define SCIP_DECL_CONSRESPROP(x)
    Definition: type_cons.h:611
    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