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