1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2022 Konrad-Zuse-Zentrum                            */
7    	/*                            fuer Informationstechnik Berlin                */
8    	/*                                                                           */
9    	/*  SCIP is distributed under the terms of the ZIB Academic License.         */
10   	/*                                                                           */
11   	/*  You should have received a copy of the ZIB Academic License              */
12   	/*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13   	/*                                                                           */
14   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15   	
16   	/**@file   cons_nonlinear.c
17   	 * @ingroup DEFPLUGINS_CONS
18   	 * @brief  constraint handler for nonlinear constraints specified by algebraic expressions
19   	 * @author Ksenia Bestuzheva
20   	 * @author Benjamin Mueller
21   	 * @author Felipe Serrano
22   	 * @author Stefan Vigerske
23   	 */
24   	
25   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26   	
27   	#ifdef SCIP_DEBUG
28   	#define ENFO_LOGGING
29   	#endif
30   	
31   	/* enable to get log output for enforcement */
32   	/* #define ENFO_LOGGING */
33   	/* define to get enforcement logging into file */
34   	/* #define ENFOLOGFILE "consexpr_enfo.log" */
35   	
36   	/* define to get more debug output from domain propagation */
37   	/* #define DEBUG_PROP */
38   	
39   	/*lint -e440*/
40   	/*lint -e441*/
41   	/*lint -e528*/
42   	/*lint -e666*/
43   	/*lint -e777*/
44   	/*lint -e866*/
45   	
46   	#include <assert.h>
47   	#include <ctype.h>
48   	
49   	#include "scip/cons_nonlinear.h"
50   	#include "scip/nlhdlr.h"
51   	#include "scip/expr_var.h"
52   	#include "scip/expr_sum.h"
53   	#include "scip/expr_value.h"
54   	#include "scip/expr_pow.h"
55   	#include "scip/nlhdlr_convex.h"
56   	#include "scip/cons_linear.h"
57   	#include "scip/cons_varbound.h"
58   	#include "scip/cons_and.h"
59   	#include "scip/cons_bounddisjunction.h"
60   	#include "scip/heur_subnlp.h"
61   	#include "scip/heur_trysol.h"
62   	#include "scip/nlpi_ipopt.h"  /* for SCIPsolveLinearEquationsIpopt */
63   	#include "scip/debug.h"
64   	#include "scip/dialog_default.h"
65   	
66   	/* fundamental constraint handler properties */
67   	#define CONSHDLR_NAME          "nonlinear"
68   	#define CONSHDLR_DESC          "handler for nonlinear constraints specified by algebraic expressions"
69   	#define CONSHDLR_ENFOPRIORITY       -60 /**< priority of the constraint handler for constraint enforcing */
70   	#define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
71   	#define CONSHDLR_EAGERFREQ          100 /**< frequency for using all instead of only the useful constraints in separation,
72   	                                         *   propagation and enforcement, -1 for no eager evaluations, 0 for first only */
73   	#define CONSHDLR_NEEDSCONS         TRUE /**< should the constraint handler be skipped, if no constraints are available? */
74   	
75   	/* optional constraint handler properties */
76   	#define CONSHDLR_SEPAPRIORITY        10 /**< priority of the constraint handler for separation */
77   	#define CONSHDLR_SEPAFREQ             1 /**< frequency for separating cuts; zero means to separate only in the root node */
78   	#define CONSHDLR_DELAYSEPA        FALSE /**< should separation method be delayed, if other separators found cuts? */
79   	
80   	#define CONSHDLR_PROPFREQ             1 /**< frequency for propagating domains; zero means only preprocessing propagation */
81   	#define CONSHDLR_DELAYPROP        FALSE /**< should propagation method be delayed, if other propagators found reductions? */
82   	#define CONSHDLR_PROP_TIMING     SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
83   	
84   	#define CONSHDLR_PRESOLTIMING    SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
85   	#define CONSHDLR_MAXPREROUNDS        -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
86   	
87   	/* properties of the nonlinear constraint handler statistics table */
88   	#define TABLE_NAME_NONLINEAR           "cons_nonlinear"
89   	#define TABLE_DESC_NONLINEAR           "nonlinear constraint handler statistics"
90   	#define TABLE_POSITION_NONLINEAR       14600                  /**< the position of the statistics table */
91   	#define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
92   	
93   	/* properties of the nonlinear handler statistics table */
94   	#define TABLE_NAME_NLHDLR              "nlhdlr"
95   	#define TABLE_DESC_NLHDLR              "nonlinear handler statistics"
96   	#define TABLE_POSITION_NLHDLR          14601                  /**< the position of the statistics table */
97   	#define TABLE_EARLIEST_STAGE_NLHDLR    SCIP_STAGE_PRESOLVING  /**< output of the statistics table is only printed from this stage onwards */
98   	
99   	#define DIALOG_NAME            "nlhdlrs"
100  	#define DIALOG_DESC            "display nonlinear handlers"
101  	#define DIALOG_ISSUBMENU          FALSE
102  	
103  	#define VERTEXPOLY_MAXPERTURBATION      1e-3 /**< maximum perturbation */
104  	#define VERTEXPOLY_USEDUALSIMPLEX       TRUE /**< use dual or primal simplex algorithm? */
105  	#define VERTEXPOLY_RANDNUMINITSEED  20181029 /**< seed for random number generator, which is used to move points away from the boundary */
106  	#define VERTEXPOLY_ADJUSTFACETFACTOR     1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
107  	
108  	#define BRANCH_RANDNUMINITSEED      20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
109  	
110  	#define BILIN_MAXNAUXEXPRS                10 /**< maximal number of auxiliary expressions per bilinear term */
111  	
112  	/** translate from one value of infinity to another
113  	 *
114  	 *  if val is &ge; infty1, then give infty2, else give val
115  	 */
116  	#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
117  	
118  	/** translates x to 2^x for non-negative integer x */
119  	#define POWEROFTWO(x) (0x1u << (x))
120  	
121  	#ifdef ENFO_LOGGING
122  	#define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
123  	FILE* enfologfile = NULL;
124  	#else
125  	#define ENFOLOG(x)
126  	#endif
127  	
128  	/*
129  	 * Data structures
130  	 */
131  	
132  	/** enforcement data of an expression */
133  	typedef struct
134  	{
135  	   SCIP_NLHDLR*          nlhdlr;             /**< nonlinear handler */
136  	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata;     /**< data of nonlinear handler */
137  	   SCIP_NLHDLR_METHOD nlhdlrparticipation; /**< methods where nonlinear handler participates */
138  	   SCIP_Bool             issepainit;         /**< was the initsepa callback of nlhdlr called */
139  	   SCIP_Real             auxvalue;           /**< auxiliary value of expression w.r.t. currently enforced solution */
140  	   SCIP_Bool             sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
141  	   SCIP_Bool             sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
142  	} EXPRENFO;
143  	
144  	/** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
145  	struct SCIP_Expr_OwnerData
146  	{
147  	   SCIP_CONSHDLR*        conshdlr;           /** nonlinear constraint handler */
148  	
149  	   /* locks and monotonicity */
150  	   int                   nlockspos;          /**< positive locks counter */
151  	   int                   nlocksneg;          /**< negative locks counter */
152  	   SCIP_MONOTONE*        monotonicity;       /**< array containing monotonicity of expression w.r.t. each child */
153  	   int                   monotonicitysize;   /**< length of monotonicity array */
154  	
155  	   /* propagation (in addition to activity that is stored in expr) */
156  	   SCIP_INTERVAL         propbounds;         /**< bounds to propagate in reverse propagation */
157  	   unsigned int          propboundstag;      /**< tag to indicate whether propbounds are valid for the current propagation rounds */
158  	   SCIP_Bool             inpropqueue;        /**< whether expression is queued for propagation */
159  	
160  	   /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
161  	   EXPRENFO**            enfos;              /**< enforcements */
162  	   int                   nenfos;             /**< number of enforcements, or -1 if not initialized */
163  	   unsigned int          lastenforced;       /**< last enforcement round where expression was enforced successfully */
164  	   unsigned int          nactivityusesprop;  /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
165  	   unsigned int          nactivityusessepa;  /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
166  	   unsigned int          nauxvaruses;        /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
167  	   SCIP_VAR*             auxvar;             /**< auxiliary variable used for outer approximation cuts */
168  	
169  	   /* branching */
170  	   SCIP_Real             violscoresum;       /**< sum of violation scores for branching stored for this expression */
171  	   SCIP_Real             violscoremax;       /**< max of violation scores for branching stored for this expression */
172  	   int                   nviolscores;        /**< number of violation scores stored for this expression */
173  	   unsigned int          violscoretag;       /**< tag to decide whether a violation score of an expression needs to be initialized */
174  	
175  	   /* additional data for variable expressions (TODO move into sub-struct?) */
176  	   SCIP_CONS**           conss;              /**< constraints in which this variable appears */
177  	   int                   nconss;             /**< current number of constraints in conss */
178  	   int                   consssize;          /**< length of conss array */
179  	   SCIP_Bool             consssorted;        /**< is the array of constraints sorted */
180  	
181  	   int                   filterpos;          /**< position of eventdata in SCIP's event filter, -1 if not catching events */
182  	};
183  	
184  	/** constraint data for nonlinear constraints */
185  	struct SCIP_ConsData
186  	{
187  	   /* data that defines the constraint: expression and sides */
188  	   SCIP_EXPR*            expr;               /**< expression that represents this constraint */
189  	   SCIP_Real             lhs;                /**< left-hand side */
190  	   SCIP_Real             rhs;                /**< right-hand side */
191  	
192  	   /* variables */
193  	   SCIP_EXPR**           varexprs;           /**< array containing all variable expressions */
194  	   int                   nvarexprs;          /**< total number of variable expressions */
195  	   SCIP_Bool             catchedevents;      /**< do we catch events on variables? */
196  	
197  	   /* constraint violation */
198  	   SCIP_Real             lhsviol;            /**< violation of left-hand side by current solution */
199  	   SCIP_Real             rhsviol;            /**< violation of right-hand side by current solution */
200  	   SCIP_Real             gradnorm;           /**< norm of gradient of constraint function in current solution (if evaluated) */
201  	   SCIP_Longint          gradnormsoltag;     /**< tag of solution used that gradnorm corresponds to */
202  	
203  	   /* status flags */
204  	   unsigned int          ispropagated:1;     /**< did we propagate the current bounds already? */
205  	   unsigned int          issimplified:1;     /**< did we simplify the expression tree already? */
206  	
207  	   /* locks */
208  	   int                   nlockspos;          /**< number of positive locks */
209  	   int                   nlocksneg;          /**< number of negative locks */
210  	
211  	   /* repair infeasible solutions */
212  	   SCIP_VAR*             linvardecr;         /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
213  	   SCIP_VAR*             linvarincr;         /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
214  	   SCIP_Real             linvardecrcoef;     /**< linear coefficient of linvardecr */
215  	   SCIP_Real             linvarincrcoef;     /**< linear coefficient of linvarincr */
216  	
217  	   /* miscellaneous */
218  	   SCIP_EXPRCURV         curv;               /**< curvature of the root expression w.r.t. the original variables */
219  	   SCIP_NLROW*           nlrow;              /**< a nonlinear row representation of this constraint */
220  	   int                   consindex;          /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
221  	};
222  	
223  	/** constraint upgrade method */
224  	typedef struct
225  	{
226  	   SCIP_DECL_NONLINCONSUPGD((*consupgd));    /**< method to call for upgrading nonlinear constraint */
227  	   int                   priority;           /**< priority of upgrading method */
228  	   SCIP_Bool             active;             /**< is upgrading enabled */
229  	} CONSUPGRADE;
230  	
231  	/** constraint handler data */
232  	struct SCIP_ConshdlrData
233  	{
234  	   /* nonlinear handler */
235  	   SCIP_NLHDLR**         nlhdlrs;            /**< nonlinear handlers */
236  	   int                   nnlhdlrs;           /**< number of nonlinear handlers */
237  	   int                   nlhdlrssize;        /**< size of nlhdlrs array */
238  	   SCIP_Bool             indetect;           /**< whether we are currently in detectNlhdlr */
239  	   SCIP_Bool             registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
240  	   SCIP_Bool             registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
241  	
242  	   /* constraint upgrades */
243  	   CONSUPGRADE**         consupgrades;       /**< constraint upgrade methods for specializing nonlinear constraints */
244  	   int                   consupgradessize;   /**< size of consupgrades array */
245  	   int                   nconsupgrades;      /**< number of constraint upgrade methods */
246  	
247  	   /* other plugins */
248  	   SCIP_EVENTHDLR*       eventhdlr;          /**< handler for variable bound change events */
249  	   SCIP_HEUR*            subnlpheur;         /**< a pointer to the subnlp heuristic, if available */
250  	   SCIP_HEUR*            trysolheur;         /**< a pointer to the trysol heuristic, if available */
251  	
252  	   /* tags and counters */
253  	   int                   auxvarid;           /**< unique id for the next auxiliary variable */
254  	   SCIP_Longint          curboundstag;       /**< tag indicating current variable bounds */
255  	   SCIP_Longint          lastboundrelax;     /**< tag when bounds where most recently relaxed */
256  	   SCIP_Longint          lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
257  	   unsigned int          enforound;          /**< total number of enforcement calls, including current one */
258  	   int                   lastconsindex;      /**< last used consindex, plus one */
259  	
260  	   /* activity intervals and domain propagation */
261  	   SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
262  	   SCIP_Bool             globalbounds;       /**< whether global variable bounds should be used for activity calculation */
263  	   SCIP_QUEUE*           reversepropqueue;   /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
264  	   SCIP_Bool             forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
265  	   unsigned int          curpropboundstag;   /**< tag indicating current propagation rounds, to match with expr->propboundstag */
266  	
267  	   /* parameters */
268  	   int                   maxproprounds;      /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
269  	   SCIP_Bool             propauxvars;        /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
270  	   char                  varboundrelax;      /**< strategy on how to relax variable bounds during bound tightening */
271  	   SCIP_Real             varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
272  	   SCIP_Real             conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
273  	   SCIP_Real             vp_maxperturb;      /**< maximal relative perturbation of reference point */
274  	   SCIP_Real             vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
275  	   SCIP_Bool             vp_dualsimplex;     /**< whether to use dual simplex instead of primal simplex for facet computing LP */
276  	   SCIP_Bool             reformbinprods;     /**< whether to reformulate products of binary variables during presolving */
277  	   SCIP_Bool             reformbinprodsand;  /**< whether to use the AND constraint handler for reformulating binary products */
278  	   int                   reformbinprodsfac;  /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
279  	   SCIP_Bool             forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
280  	   SCIP_Bool             tightenlpfeastol;   /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
281  	   SCIP_Bool             propinenforce;      /**< whether to (re)run propagation in enforcement */
282  	   SCIP_Real             weakcutthreshold;   /**< threshold for when to regard a cut from an estimator as weak */
283  	   SCIP_Real             strongcutmaxcoef;   /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
284  	   SCIP_Bool             strongcutefficacy;  /**< consider efficacy requirement when deciding whether a cut is "strong" */
285  	   SCIP_Bool             forcestrongcut;     /**< whether to force "strong" cuts in enforcement */
286  	   SCIP_Real             enfoauxviolfactor;  /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
287  	   SCIP_Real             weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
288  	   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 */
289  	   char                  violscale;          /**< method how to scale violations to make them comparable (not used for feasibility check) */
290  	   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) */
291  	   int                   branchauxmindepth;  /**< from which depth on to allow branching on auxiliary variables */
292  	   SCIP_Bool             branchexternal;     /**< whether to use external branching candidates for branching */
293  	   SCIP_Real             branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
294  	   SCIP_Real             branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
295  	   SCIP_Real             branchviolweight;   /**< weight by how much to consider the violation assigned to a variable for its branching score */
296  	   SCIP_Real             branchdualweight;   /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
297  	   SCIP_Real             branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
298  	   SCIP_Real             branchdomainweight; /**< weight by how much to consider the domain width in branching score */
299  	   SCIP_Real             branchvartypeweight;/**< weight by how much to consider variable type in branching score */
300  	   char                  branchscoreagg;     /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
301  	   char                  branchviolsplit;    /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
302  	   SCIP_Real             branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
303  	   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) */
304  	   SCIP_Bool             assumeconvex;       /**< whether to assume that any constraint is convex */
305  	
306  	   /* statistics */
307  	   SCIP_Longint          nweaksepa;          /**< number of times we used "weak" cuts for enforcement */
308  	   SCIP_Longint          ntightenlp;         /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
309  	   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 */
310  	   SCIP_Longint          ndesperatebranch;   /**< number of times we branched on some variable because normal enforcement was not successful */
311  	   SCIP_Longint          ndesperatecutoff;   /**< number of times we cut off a node in enforcement because no branching candidate could be found */
312  	   SCIP_Longint          nforcelp;           /**< number of times we forced solving the LP when enforcing a pseudo solution */
313  	   SCIP_CLOCK*           canonicalizetime;   /**< time spend for canonicalization */
314  	   SCIP_Longint          ncanonicalizecalls; /**< number of times we called canonicalization */
315  	
316  	   /* facets of envelops of vertex-polyhedral functions */
317  	   SCIP_RANDNUMGEN*      vp_randnumgen;      /**< random number generator used to perturb reference point */
318  	   SCIP_LPI*             vp_lp[SCIP_MAXVERTEXPOLYDIM+1];  /**< LPs used to compute facets for functions of different dimension */
319  	
320  	   /* hashing of bilinear terms */
321  	   SCIP_HASHTABLE*       bilinhashtable;     /**< hash table for bilinear terms */
322  	   SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
323  	   int                   nbilinterms;        /**< total number of bilinear terms */
324  	   int                   bilintermssize;     /**< size of bilinterms array */
325  	   int                   bilinmaxnauxexprs;  /**< maximal number of auxiliary expressions per bilinear term */
326  	
327  	   /* branching */
328  	   SCIP_RANDNUMGEN*      branchrandnumgen;   /**< random number generated used in branching variable selection */
329  	   char                  branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
330  	
331  	   /* misc */
332  	   SCIP_Bool             checkedvarlocks;    /**< whether variables contained in a single constraint have been already considered */
333  	   SCIP_HASHMAP*         var2expr;           /**< hashmap to map SCIP variables to variable-expressions */
334  	   int                   newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
335  	};
336  	
337  	/** branching candidate with various scores */
338  	typedef struct
339  	{
340  	   SCIP_EXPR*            expr;               /**< expression that holds branching candidate */
341  	   SCIP_Real             auxviol;            /**< aux-violation score of candidate */
342  	   SCIP_Real             domain;             /**< domain score of candidate */
343  	   SCIP_Real             dual;               /**< dual score of candidate */
344  	   SCIP_Real             pscost;             /**< pseudo-cost score of candidate */
345  	   SCIP_Real             vartype;            /**< variable type score of candidate */
346  	   SCIP_Real             weighted;           /**< weighted sum of other scores, see scoreBranchingCandidates() */
347  	} BRANCHCAND;
348  	
349  	/*
350  	 * Local methods
351  	 */
352  	
353  	/* forward declaration */
354  	static
355  	SCIP_RETCODE forwardPropExpr(
356  	   SCIP*                 scip,               /**< SCIP data structure */
357  	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
358  	   SCIP_EXPR*            rootexpr,           /**< expression */
359  	   SCIP_Bool             tightenauxvars,     /**< should the bounds of auxiliary variables be tightened? */
360  	   SCIP_Bool*            infeasible,         /**< buffer to store whether the problem is infeasible (NULL if not needed) */
361  	   int*                  ntightenings        /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
362  	   );
363  	
364  	/** frees auxiliary variables of expression, if any */
365  	static
366  	SCIP_RETCODE freeAuxVar(
367  	   SCIP*                 scip,               /**< SCIP data structure */
368  	   SCIP_EXPR*            expr                /**< expression which auxvar to free, if any */
369  	   )
370  	{
371  	   SCIP_EXPR_OWNERDATA* mydata;
372  	
373  	   assert(scip != NULL);
374  	   assert(expr != NULL);
375  	
376  	   mydata = SCIPexprGetOwnerData(expr);
377  	   assert(mydata != NULL);
378  	
379  	   if( mydata->auxvar == NULL )
380  	      return SCIP_OKAY;
381  	
382  	   SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
383  	
384  	   /* remove variable locks
385  	    * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
386  	    */
387  	   SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
388  	
389  	   /* release auxiliary variable */
390  	   SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
391  	   assert(mydata->auxvar == NULL);
392  	
393  	   return SCIP_OKAY;
394  	}
395  	
396  	/** frees data used for enforcement of expression, that is, nonlinear handlers
397  	 *
398  	 * can also clear indicators whether expr needs enforcement methods, that is,
399  	 * free an associated auxiliary variable and reset the nactivityuses counts
400  	 */
401  	static
402  	SCIP_RETCODE freeEnfoData(
403  	   SCIP*                 scip,               /**< SCIP data structure */
404  	   SCIP_EXPR*            expr,               /**< expression whose enforcement data will be released */
405  	   SCIP_Bool             freeauxvar          /**< whether aux var should be released and activity usage counts be reset */
406  	   )
407  	{
408  	   SCIP_EXPR_OWNERDATA* mydata;
409  	   int e;
410  	
411  	   mydata = SCIPexprGetOwnerData(expr);
412  	   assert(mydata != NULL);
413  	
414  	   if( freeauxvar )
415  	   {
416  	      /* free auxiliary variable */
417  	      SCIP_CALL( freeAuxVar(scip, expr) );
418  	      assert(mydata->auxvar == NULL);
419  	
420  	      /* reset count on activity and auxvar usage */
421  	      mydata->nactivityusesprop = 0;
422  	      mydata->nactivityusessepa = 0;
423  	      mydata->nauxvaruses = 0;
424  	   }
425  	
426  	   /* free data stored by nonlinear handlers */
427  	   for( e = 0; e < mydata->nenfos; ++e )
428  	   {
429  	      SCIP_NLHDLR* nlhdlr;
430  	
431  	      assert(mydata->enfos[e] != NULL);
432  	
433  	      nlhdlr = mydata->enfos[e]->nlhdlr;
434  	      assert(nlhdlr != NULL);
435  	
436  	      if( mydata->enfos[e]->issepainit )
437  	      {
438  	         /* call the separation deinitialization callback of the nonlinear handler */
439  	         SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
440  	         mydata->enfos[e]->issepainit = FALSE;
441  	      }
442  	
443  	      /* free nlhdlr exprdata, if there is any and there is a method to free this data */
444  	      if( mydata->enfos[e]->nlhdlrexprdata != NULL )
445  	      {
446  	         SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
447  	         assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
448  	      }
449  	
450  	      /* free enfo data */
451  	      SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
452  	   }
453  	
454  	   /* free array with enfo data */
455  	   SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
456  	
457  	   /* we need to look at this expression in detect again */
458  	   mydata->nenfos = -1;
459  	
460  	   return SCIP_OKAY;
461  	}
462  	
463  	/** callback that frees data that this conshdlr stored in an expression */
464  	static
465  	SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
466  	{
467  	   assert(scip != NULL);
468  	   assert(expr != NULL);
469  	   assert(ownerdata != NULL);
470  	   assert(*ownerdata != NULL);
471  	
472  	   /* expression should not be locked anymore */
473  	   assert((*ownerdata)->nlockspos == 0);
474  	   assert((*ownerdata)->nlocksneg == 0);
475  	
476  	   SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
477  	
478  	   /* expression should not be enforced anymore */
479  	   assert((*ownerdata)->nenfos <= 0);
480  	   assert((*ownerdata)->auxvar == NULL);
481  	
482  	   if( SCIPisExprVar(scip, expr) )
483  	   {
484  	      SCIP_CONSHDLRDATA* conshdlrdata;
485  	      SCIP_VAR* var;
486  	
487  	      /* there should be no constraints left that still use this variable */
488  	      assert((*ownerdata)->nconss == 0);
489  	      /* thus, there should also be no variable event catched (via this exprhdlr) */
490  	      assert((*ownerdata)->filterpos == -1);
491  	
492  	      SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
493  	
494  	      /* update var2expr hashmap in conshdlrdata */
495  	      conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
496  	      assert(conshdlrdata != NULL);
497  	
498  	      var = SCIPgetVarExprVar(expr);
499  	      assert(var != NULL);
500  	
501  	      /* remove var -> expr map from hashmap if present
502  	       *  (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
503  	       *   if variable-expression stored for var is different, then also do nothing)
504  	       */
505  	      if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
506  	      {
507  	         SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
508  	      }
509  	   }
510  	
511  	   SCIPfreeBlockMemory(scip, ownerdata);
512  	
513  	   return SCIP_OKAY;
514  	}
515  	
516  	static
517  	SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
518  	{  /*lint --e{715}*/
519  	   assert(ownerdata != NULL);
520  	
521  	   /* print nl handlers associated to expr */
522  	   if( ownerdata->nenfos > 0 )
523  	   {
524  	      int i;
525  	      SCIPinfoMessage(scip, file, "   {");
526  	
527  	      for( i = 0; i < ownerdata->nenfos; ++i )
528  	      {
529  	         SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
530  	         if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
531  	            SCIPinfoMessage(scip, file, "a");
532  	         if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
533  	            SCIPinfoMessage(scip, file, "u");
534  	         if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
535  	            SCIPinfoMessage(scip, file, "o");
536  	         if( i < ownerdata->nenfos-1 )
537  	            SCIPinfoMessage(scip, file, ", ");
538  	      }
539  	
540  	      SCIPinfoMessage(scip, file, "}");
541  	   }
542  	
543  	   /* print aux var associated to expr */
544  	   if( ownerdata->auxvar != NULL )
545  	   {
546  	      SCIPinfoMessage(scip, file, "  (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
547  	   }
548  	   SCIPinfoMessage(scip, file, "\n");
549  	
550  	   return SCIP_OKAY;
551  	}
552  	
553  	/** possibly reevaluates and then returns the activity of the expression
554  	 *
555  	 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
556  	 */
557  	static
558  	SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
559  	{
560  	   SCIP_CONSHDLRDATA* conshdlrdata;
561  	
562  	   assert(scip != NULL);
563  	   assert(expr != NULL);
564  	   assert(ownerdata != NULL);
565  	
566  	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
567  	   assert(conshdlrdata != NULL);
568  	
569  	   if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
570  	   {
571  	      /* update activity of expression */
572  	      SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
573  	
574  	      assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
575  	   }
576  	
577  	   return SCIP_OKAY;
578  	}
579  	
580  	/** callback that creates data that this conshdlr wants to store in an expression */
581  	static
582  	SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
583  	{
584  	   assert(scip != NULL);
585  	   assert(expr != NULL);
586  	   assert(ownerdata != NULL);
587  	
588  	   SCIP_CALL( SCIPallocClearBlockMemory(scip, ownerdata) );
589  	   (*ownerdata)->nenfos = -1;
590  	   (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
591  	
592  	   if( SCIPisExprVar(scip, expr) )
593  	   {
594  	      SCIP_CONSHDLRDATA* conshdlrdata;
595  	      SCIP_VAR* var;
596  	
597  	      (*ownerdata)->filterpos = -1;
598  	
599  	      /* add to var2expr hashmap if not having expr for var yet */
600  	
601  	      conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
602  	      assert(conshdlrdata != NULL);
603  	
604  	      var = SCIPgetVarExprVar(expr);
605  	
606  	      if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
607  	      {
608  	         /* store the variable expression in the hashmap */
609  	         SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
610  	      }
611  	      else
612  	      {
613  	         /* if expr was just created, then it shouldn't already be stored as image of var */
614  	         assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
615  	      }
616  	   }
617  	   else
618  	   {
619  	      /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
620  	      (*ownerdata)->filterpos = -2;
621  	   }
622  	
623  	   *ownerfree = exprownerFree;
624  	   *ownerprint = exprownerPrint;
625  	   *ownerevalactivity = exprownerEvalactivity;
626  	
627  	   return SCIP_OKAY;
628  	}
629  	
630  	/** creates a variable expression or retrieves from hashmap in conshdlr data */
631  	static
632  	SCIP_RETCODE createExprVar(
633  	   SCIP*                 scip,               /**< SCIP data structure */
634  	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
635  	   SCIP_EXPR**           expr,               /**< pointer where to store expression */
636  	   SCIP_VAR*             var                 /**< variable to be stored */
637  	   )
638  	{
639  	   assert(conshdlr != NULL);
640  	   assert(expr != NULL);
641  	   assert(var != NULL);
642  	
643  	   /* get variable expression representing the given variable if there is one already */
644  	   *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
645  	
646  	   if( *expr == NULL )
647  	   {
648  	      /* create a new variable expression; this also captures the expression */
649  	      SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
650  	      assert(*expr != NULL);
651  	      /* exprownerCreate should have added var->expr to var2expr */
652  	      assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
653  	   }
654  	   else
655  	   {
656  	      /* only capture already existing expr to get a consistent uses-count */
657  	      SCIPcaptureExpr(*expr);
658  	   }
659  	
660  	   return SCIP_OKAY;
661  	}
662  	
663  	/* map var exprs to var-expr from var2expr hashmap */
664  	static
665  	SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
666  	{  /*lint --e{715}*/
667  	   SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
668  	
669  	   assert(sourcescip != NULL);
670  	   assert(targetscip != NULL);
671  	   assert(sourceexpr != NULL);
672  	   assert(targetexpr != NULL);
673  	   assert(*targetexpr == NULL);
674  	   assert(mapexprdata != NULL);
675  	
676  	   /* do not provide map if not variable */
677  	   if( !SCIPisExprVar(sourcescip, sourceexpr) )
678  	      return SCIP_OKAY;
679  	
680  	   SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
681  	
682  	   return SCIP_OKAY;
683  	}
684  	
685  	/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
686  	static
687  	SCIP_DECL_EXPR_MAPEXPR(mapexprtransvar)
688  	{  /*lint --e{715}*/
689  	   SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
690  	   SCIP_VAR* var;
691  	
692  	   assert(sourcescip != NULL);
693  	   assert(targetscip != NULL);
694  	   assert(sourceexpr != NULL);
695  	   assert(targetexpr != NULL);
696  	   assert(*targetexpr == NULL);
697  	   assert(mapexprdata != NULL);
698  	
699  	   /* do not provide map if not variable */
700  	   if( !SCIPisExprVar(sourcescip, sourceexpr) )
701  	      return SCIP_OKAY;
702  	
703  	   var = SCIPgetVarExprVar(sourceexpr);
704  	   assert(var != NULL);
705  	
706  	   /* transform variable */
707  	   SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
708  	   assert(var != NULL);
709  	
710  	   SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
711  	
712  	   return SCIP_OKAY;
713  	}
714  	
715  	/** stores all variable expressions into a given constraint */
716  	static
717  	SCIP_RETCODE storeVarExprs(
718  	   SCIP*                 scip,               /**< SCIP data structure */
719  	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
720  	   SCIP_CONSDATA*        consdata            /**< constraint data */
721  	   )
722  	{
723  	   SCIP_CONSHDLRDATA* conshdlrdata;
724  	   int varexprssize;
725  	   int i;
726  	
727  	   assert(consdata != NULL);
728  	
729  	   /* skip if we have stored the variable expressions already */
730  	   if( consdata->varexprs != NULL )
731  	      return SCIP_OKAY;
732  	
733  	   assert(consdata->varexprs == NULL);
734  	   assert(consdata->nvarexprs == 0);
735  	
736  	   /* get an upper bound on number of variable expressions */
737  	   if( consdata->issimplified )
738  	   {
739  	      /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
740  	       * so we cannot have more variable expression than the number of active variables
741  	       */
742  	      varexprssize = SCIPgetNVars(scip);
743  	   }
744  	   else
745  	   {
746  	      SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
747  	   }
748  	
749  	   /* create array to store all variable expressions */
750  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
751  	
752  	   SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
753  	   assert(varexprssize >= consdata->nvarexprs);
754  	
755  	   /* shrink array if there are less variables in the expression than in the problem */
756  	   if( varexprssize > consdata->nvarexprs )
757  	   {
758  	      SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
759  	   }
760  	
761  	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
762  	   assert(conshdlrdata != NULL);
763  	   assert(conshdlrdata->var2expr != NULL);
764  	
765  	   /* ensure that for every variable an entry exists in the var2expr hashmap
766  	    * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
767  	    */
768  	   for( i = 0; i < consdata->nvarexprs; ++i )
769  	   {
770  	      if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
771  	      {
772  	         SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
773  	      }
774  	   }
775  	
776  	   return SCIP_OKAY;
777  	}
778  	
779  	/** frees all variable expression stored in storeVarExprs() */
780  	static
781  	SCIP_RETCODE freeVarExprs(
782  	   SCIP*                 scip,               /**< SCIP data structure */
783  	   SCIP_CONSDATA*        consdata            /**< constraint data */
784  	   )
785  	{
786  	   int i;
787  	
788  	   assert(consdata != NULL);
789  	
790  	   /* skip if we have stored the variable expressions already*/
791  	   if( consdata->varexprs == NULL )
792  	      return SCIP_OKAY;
793  	
794  	   assert(consdata->varexprs != NULL);
795  	   assert(consdata->nvarexprs >= 0);
796  	
797  	   /* release variable expressions */
798  	   for( i = 0; i < consdata->nvarexprs; ++i )
799  	   {
800  	      assert(consdata->varexprs[i] != NULL);
801  	      SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
802  	      assert(consdata->varexprs[i] == NULL);
803  	   }
804  	
805  	   /* free variable expressions */
806  	   SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
807  	   consdata->varexprs = NULL;
808  	   consdata->nvarexprs = 0;
809  	
810  	   return SCIP_OKAY;
811  	}
812  	
813  	/** interval evaluation of variables as used in bound tightening
814  	 *
815  	 * Returns slightly relaxed local variable bounds of a variable as interval.
816  	 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
817  	 */
818  	static
819  	SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
820  	{
821  	   SCIP_INTERVAL interval;
822  	   SCIP_CONSHDLRDATA* conshdlrdata;
823  	   SCIP_Real lb;
824  	   SCIP_Real ub;
825  	
826  	   assert(scip != NULL);
827  	   assert(var != NULL);
828  	
829  	   conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
830  	   assert(conshdlrdata != NULL);
831  	
832  	   if( conshdlrdata->globalbounds )
833  	   {
834  	      lb = SCIPvarGetLbGlobal(var);
835  	      ub = SCIPvarGetUbGlobal(var);
836  	   }
837  	   else
838  	   {
839  	      lb = SCIPvarGetLbLocal(var);
840  	      ub = SCIPvarGetUbLocal(var);
841  	   }
842  	   assert(lb <= ub);  /* SCIP should ensure that variable bounds are not contradicting */
843  	
844  	   /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
845  	   if( SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT )
846  	   {
847  	      lb = EPSROUND(lb, 0.0); /*lint !e835*/
848  	      ub = EPSROUND(ub, 0.0); /*lint !e835*/
849  	   }
850  	
851  	   /* integer variables should always have integral bounds in SCIP */
852  	   assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var));  /*lint !e835*/
853  	   assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var));  /*lint !e835*/
854  	
855  	   switch( conshdlrdata->varboundrelax )
856  	   {
857  	      case 'n' : /* no relaxation */
858  	         break;
859  	
860  	      case 'a' : /* relax by absolute value */
861  	      {
862  	         /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
863  	         if( SCIPvarIsIntegral(var) )
864  	            break;
865  	
866  	         if( !SCIPisInfinity(scip, -lb) )
867  	         {
868  	            /* reduce lb by epsilon, or to the next integer value, which ever is larger */
869  	            SCIP_Real bnd = floor(lb);
870  	            lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
871  	         }
872  	
873  	         if( !SCIPisInfinity(scip, ub) )
874  	         {
875  	            /* increase ub by epsilon, or to the next integer value, which ever is smaller */
876  	            SCIP_Real bnd = ceil(ub);
877  	            ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
878  	         }
879  	
880  	         break;
881  	      }
882  	
883  	      case 'b' : /* relax always by absolute value */
884  	      {
885  	         /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
886  	         if( SCIPvarIsIntegral(var) )
887  	            break;
888  	
889  	         if( !SCIPisInfinity(scip, -lb) )
890  	            lb -= conshdlrdata->varboundrelaxamount;
891  	
892  	         if( !SCIPisInfinity(scip, ub) )
893  	            ub += conshdlrdata->varboundrelaxamount;
894  	
895  	         break;
896  	      }
897  	
898  	      case 'r' : /* relax by relative value */
899  	      {
900  	         /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
901  	         if( SCIPvarIsIntegral(var) )
902  	            break;
903  	
904  	         /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
905  	          * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
906  	          * further, do not relax beyond next integer value
907  	          */
908  	         if( !SCIPisInfinity(scip, -lb) )
909  	         {
910  	            SCIP_Real bnd = floor(lb);
911  	            lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
912  	         }
913  	
914  	         if( !SCIPisInfinity(scip, ub) )
915  	         {
916  	            SCIP_Real bnd = ceil(ub);
917  	            ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
918  	         }
919  	
920  	         break;
921  	      }
922  	
923  	      default :
924  	      {
925  	         SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
926  	         SCIPABORT();
927  	         break;
928  	      }
929  	   }
930  	
931  	   /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
932  	   lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
933  	   ub =  infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, ub);
934  	   assert(lb <= ub);
935  	
936  	   SCIPintervalSetBounds(&interval, lb, ub);
937  	
938  	   return interval;
939  	}
940  	
941  	/** compares two nonlinear constraints by its index
942  	 *
943  	 * Usable as compare operator in array sort functions.
944  	 */
945  	static
946  	SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
947  	{
948  	   SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
949  	   SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
950  	
951  	   assert(consdata1 != NULL);
952  	   assert(consdata2 != NULL);
953  	
954  	   return consdata1->consindex - consdata2->consindex;
955  	}
956  	
957  	/** processes variable fixing or bound change event */
958  	static
959  	SCIP_DECL_EVENTEXEC(processVarEvent)
960  	{  /*lint --e{715}*/
961  	   SCIP_EVENTTYPE eventtype;
962  	   SCIP_EXPR* expr;
963  	   SCIP_EXPR_OWNERDATA* ownerdata;
964  	
965  	   eventtype = SCIPeventGetType(event);
966  	   assert(eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED));
967  	
968  	   assert(eventdata != NULL);
969  	   expr = (SCIP_EXPR*) eventdata;
970  	   assert(SCIPisExprVar(scip, expr));
971  	
972  	   SCIPdebugMsg(scip, "  exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
973  	         SCIPvarGetName(SCIPeventGetVar(event)),
974  	         SCIPvarGetLbLocal(SCIPeventGetVar(event)), SCIPvarGetUbLocal(SCIPeventGetVar(event)),
975  	         SCIPvarGetLbGlobal(SCIPeventGetVar(event)), SCIPvarGetUbGlobal(SCIPeventGetVar(event)));
976  	
977  	   ownerdata = SCIPexprGetOwnerData(expr);
978  	   assert(ownerdata != NULL);
979  	   /* we only catch varevents for variables in constraints, so there should be constraints */
980  	   assert(ownerdata->nconss > 0);
981  	   assert(ownerdata->conss != NULL);
982  	
983  	   /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
984  	    * - propagation can only find something new if a bound was tightened
985  	    * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
986  	    *   and we look at global changes (that is, we are not looking at boundchanges in probing)
987  	    */
988  	   if( eventtype & (SCIP_EVENTTYPE_BOUNDTIGHTENED | SCIP_EVENTTYPE_VARFIXED) )
989  	   {
990  	      SCIP_CONSDATA* consdata;
991  	      int c;
992  	
993  	      for( c = 0; c < ownerdata->nconss; ++c )
994  	      {
995  	         assert(ownerdata->conss[c] != NULL);
996  	         consdata = SCIPconsGetData(ownerdata->conss[c]);
997  	
998  	         /* if bound tightening, then mark constraints to be propagated again
999  	          * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1000 	          *   that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1001 	          *   the locks don't help since they are not available separately for each constraint
1002 	          */
1003 	         if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1004 	         {
1005 	            consdata->ispropagated = FALSE;
1006 	            SCIPdebugMsg(scip, "  marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1007 	         }
1008 	
1009 	         /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1010 	         if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !SCIPinProbing(scip) )
1011 	         {
1012 	            consdata->issimplified = FALSE;
1013 	            SCIPdebugMsg(scip, "  marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1014 	         }
1015 	      }
1016 	   }
1017 	
1018 	   /* update curboundstag, lastboundrelax, and expr activity */
1019 	   if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1020 	   {
1021 	      SCIP_CONSHDLRDATA* conshdlrdata;
1022 	      SCIP_INTERVAL activity;
1023 	
1024 	      conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1025 	      assert(conshdlrdata != NULL);
1026 	
1027 	      /* increase tag on bounds */
1028 	      ++conshdlrdata->curboundstag;
1029 	      assert(conshdlrdata->curboundstag > 0);
1030 	
1031 	      /* remember also if we relaxed bounds now */
1032 	      if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1033 	         conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1034 	
1035 	      /* update the activity of the var-expr here immediately
1036 	       * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1037 	       */
1038 	      SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1039 	      /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1040 	#ifdef DEBUG_PROP
1041 	      SCIPdebugMsg(scip, "  var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1042 	#endif
1043 	      SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1044 	   }
1045 	
1046 	   return SCIP_OKAY;
1047 	}
1048 	
1049 	/** registers event handler to catch variable events on variable
1050 	 *
1051 	 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1052 	 * When an event occurs, all stored constraints are notified.
1053 	 */
1054 	static
1055 	SCIP_RETCODE catchVarEvent(
1056 	   SCIP*                 scip,               /**< SCIP data structure */
1057 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1058 	   SCIP_EXPR*            expr,               /**< variable expression */
1059 	   SCIP_CONS*            cons                /**< nonlinear constraint */
1060 	   )
1061 	{
1062 	   SCIP_EXPR_OWNERDATA* ownerdata;
1063 	
1064 	   assert(eventhdlr != NULL);
1065 	   assert(expr != NULL);
1066 	   assert(SCIPisExprVar(scip, expr));
1067 	   assert(cons != NULL);
1068 	
1069 	   ownerdata = SCIPexprGetOwnerData(expr);
1070 	   assert(ownerdata != NULL);
1071 	
1072 	#ifndef NDEBUG
1073 	   /* assert that constraint does not double-catch variable */
1074 	   {
1075 	      int i;
1076 	      for( i = 0; i < ownerdata->nconss; ++i )
1077 	         assert(ownerdata->conss[i] != cons);
1078 	   }
1079 	#endif
1080 	
1081 	   /* append cons to ownerdata->conss */
1082 	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1083 	   ownerdata->conss[ownerdata->nconss++] = cons;
1084 	   /* we're not capturing the constraint here to avoid circular references */
1085 	
1086 	   /* updated sorted flag */
1087 	   if( ownerdata->nconss <= 1 )
1088 	      ownerdata->consssorted = TRUE;
1089 	   else if( ownerdata->consssorted )
1090 	      ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1091 	
1092 	   /* catch variable events, if not done so yet (first constraint) */
1093 	   if( ownerdata->filterpos < 0 )
1094 	   {
1095 	      SCIP_EVENTTYPE eventtype;
1096 	
1097 	      assert(ownerdata->nconss == 1);
1098 	
1099 	      eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED;
1100 	
1101 	      SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1102 	      assert(ownerdata->filterpos >= 0);
1103 	   }
1104 	
1105 	   return SCIP_OKAY;
1106 	}
1107 	
1108 	/** catch variable events */
1109 	static
1110 	SCIP_RETCODE catchVarEvents(
1111 	   SCIP*                 scip,               /**< SCIP data structure */
1112 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1113 	   SCIP_CONS*            cons                /**< constraint for which to catch bound change events */
1114 	   )
1115 	{
1116 	   SCIP_CONSHDLRDATA* conshdlrdata;
1117 	   SCIP_CONSDATA* consdata;
1118 	   SCIP_EXPR* expr;
1119 	   int i;
1120 	
1121 	   assert(eventhdlr != NULL);
1122 	   assert(cons != NULL);
1123 	
1124 	   consdata = SCIPconsGetData(cons);
1125 	   assert(consdata != NULL);
1126 	   assert(consdata->varexprs != NULL);
1127 	   assert(consdata->nvarexprs >= 0);
1128 	
1129 	   /* check if we have catched variable events already */
1130 	   if( consdata->catchedevents )
1131 	      return SCIP_OKAY;
1132 	
1133 	   conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1134 	   assert(conshdlrdata != NULL);
1135 	   assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1136 	
1137 	   SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1138 	
1139 	   for( i = 0; i < consdata->nvarexprs; ++i )
1140 	   {
1141 	      expr = consdata->varexprs[i];
1142 	
1143 	      assert(expr != NULL);
1144 	      assert(SCIPisExprVar(scip, expr));
1145 	
1146 	      SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1147 	
1148 	      /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1149 	       * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1150 	       */
1151 	      if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1152 	      {
1153 	         SCIP_INTERVAL activity;
1154 	         SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1155 	         /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1156 	         SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1157 	#ifdef DEBUG_PROP
1158 	         SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1159 	#endif
1160 	      }
1161 	   }
1162 	
1163 	   consdata->catchedevents = TRUE;
1164 	
1165 	   return SCIP_OKAY;
1166 	}
1167 	
1168 	/** unregisters event handler to catch variable events on variable
1169 	 *
1170 	 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1171 	 * If this was the last constraint, then the event handler is unregistered for this variable.
1172 	 */
1173 	static
1174 	SCIP_RETCODE dropVarEvent(
1175 	   SCIP*                 scip,               /**< SCIP data structure */
1176 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1177 	   SCIP_EXPR*            expr,               /**< variable expression */
1178 	   SCIP_CONS*            cons                /**< expr constraint */
1179 	   )
1180 	{
1181 	   SCIP_EXPR_OWNERDATA* ownerdata;
1182 	   int pos;
1183 	
1184 	   assert(eventhdlr != NULL);
1185 	   assert(expr != NULL);
1186 	   assert(SCIPisExprVar(scip, expr));
1187 	   assert(cons != NULL);
1188 	
1189 	   ownerdata = SCIPexprGetOwnerData(expr);
1190 	   assert(ownerdata != NULL);
1191 	   assert(ownerdata->nconss > 0);
1192 	
1193 	   if( ownerdata->conss[ownerdata->nconss-1] == cons )
1194 	   {
1195 	      pos = ownerdata->nconss-1;
1196 	   }
1197 	   else
1198 	   {
1199 	      if( !ownerdata->consssorted )
1200 	      {
1201 	         SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1202 	         ownerdata->consssorted = TRUE;
1203 	      }
1204 	
1205 	      if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1206 	      {
1207 	         SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1208 	         return SCIP_ERROR;
1209 	      }
1210 	      assert(pos >= 0 && pos < ownerdata->nconss);
1211 	   }
1212 	   assert(ownerdata->conss[pos] == cons);
1213 	
1214 	   /* move last constraint into position of removed constraint */
1215 	   if( pos < ownerdata->nconss-1 )
1216 	   {
1217 	      ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1218 	      ownerdata->consssorted = FALSE;
1219 	   }
1220 	   --ownerdata->nconss;
1221 	
1222 	   /* drop variable events if that was the last constraint */
1223 	   if( ownerdata->nconss == 0 )
1224 	   {
1225 	      SCIP_EVENTTYPE eventtype;
1226 	
1227 	      assert(ownerdata->filterpos >= 0);
1228 	
1229 	      eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED;
1230 	
1231 	      SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1232 	      ownerdata->filterpos = -1;
1233 	   }
1234 	
1235 	   return SCIP_OKAY;
1236 	}
1237 	
1238 	/** drop variable events */
1239 	static
1240 	SCIP_RETCODE dropVarEvents(
1241 	   SCIP*                 scip,               /**< SCIP data structure */
1242 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1243 	   SCIP_CONS*            cons                /**< constraint for which to drop bound change events */
1244 	   )
1245 	{
1246 	   SCIP_CONSDATA* consdata;
1247 	   int i;
1248 	
1249 	   assert(eventhdlr != NULL);
1250 	   assert(cons != NULL);
1251 	
1252 	   consdata = SCIPconsGetData(cons);
1253 	   assert(consdata != NULL);
1254 	
1255 	   /* check if we have catched variable events already */
1256 	   if( !consdata->catchedevents )
1257 	      return SCIP_OKAY;
1258 	
1259 	   assert(consdata->varexprs != NULL);
1260 	   assert(consdata->nvarexprs >= 0);
1261 	
1262 	   SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1263 	
1264 	   for( i = consdata->nvarexprs - 1; i >= 0; --i )
1265 	   {
1266 	      assert(consdata->varexprs[i] != NULL);
1267 	
1268 	      SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1269 	   }
1270 	
1271 	   consdata->catchedevents = FALSE;
1272 	
1273 	   return SCIP_OKAY;
1274 	}
1275 	
1276 	/** creates and captures a nonlinear constraint
1277 	 *
1278 	 * @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
1279 	 */
1280 	static
1281 	SCIP_RETCODE createCons(
1282 	   SCIP*                 scip,               /**< SCIP data structure */
1283 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1284 	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
1285 	   const char*           name,               /**< name of constraint */
1286 	   SCIP_EXPR*            expr,               /**< expression of constraint (must not be NULL) */
1287 	   SCIP_Real             lhs,                /**< left hand side of constraint */
1288 	   SCIP_Real             rhs,                /**< right hand side of constraint */
1289 	   SCIP_Bool             copyexpr,           /**< whether to copy the expression or reuse the given expr (capture it) */
1290 	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
1291 	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1292 	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
1293 	                                              *   Usually set to TRUE. */
1294 	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
1295 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
1296 	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
1297 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
1298 	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
1299 	                                              *   Usually set to TRUE. */
1300 	   SCIP_Bool             local,              /**< is constraint only valid locally?
1301 	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1302 	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
1303 	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
1304 	                                              *   adds coefficients to this constraint. */
1305 	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
1306 	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
1307 	                                              *   are separated as constraints. */
1308 	   SCIP_Bool             removable           /**< should the relaxation be removed from the LP due to aging or cleanup?
1309 	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1310 	   )
1311 	{
1312 	   SCIP_CONSHDLRDATA* conshdlrdata;
1313 	   SCIP_CONSDATA* consdata;
1314 	
1315 	   assert(conshdlr != NULL);
1316 	   assert(expr != NULL);
1317 	
1318 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1319 	   assert(conshdlrdata != NULL);
1320 	
1321 	   if( local && SCIPgetDepth(scip) != 0 )
1322 	   {
1323 	      SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1324 	      return SCIP_INVALIDCALL;
1325 	   }
1326 	
1327 	   /* TODO we should allow for non-initial nonlinear constraints */
1328 	   if( !initial )
1329 	   {
1330 	      SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1331 	      return SCIP_INVALIDCALL;
1332 	   }
1333 	
1334 	   /* create constraint data */
1335 	   SCIP_CALL( SCIPallocClearBlockMemory(scip, &consdata) );
1336 	
1337 	   if( copyexpr )
1338 	   {
1339 	      /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1340 	      SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1341 	   }
1342 	   else
1343 	   {
1344 	      consdata->expr = expr;
1345 	      SCIPcaptureExpr(consdata->expr);
1346 	   }
1347 	   consdata->lhs = lhs;
1348 	   consdata->rhs = rhs;
1349 	   consdata->consindex = conshdlrdata->lastconsindex++;
1350 	   consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1351 	
1352 	   /* create constraint */
1353 	   SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1354 	         local, modifiable, dynamic, removable, FALSE) );
1355 	
1356 	   return SCIP_OKAY;
1357 	}
1358 	
1359 	/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1360 	 *
1361 	 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1362 	 * Assume that f(x) is associated with auxiliary variable z.
1363 	 *
1364 	 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1365 	 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1366 	 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1367 	 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1368 	 *
1369 	 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1370 	 */
1371 	static
1372 	SCIP_Real getExprAbsOrigViolation(
1373 	   SCIP*                 scip,               /**< SCIP data structure */
1374 	   SCIP_EXPR*            expr,               /**< expression */
1375 	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
1376 	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(x) is violated, or NULL */
1377 	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(x) is violated, or NULL */
1378 	   )
1379 	{
1380 	   SCIP_EXPR_OWNERDATA* ownerdata;
1381 	   SCIP_Real auxvarvalue;
1382 	
1383 	   assert(expr != NULL);
1384 	
1385 	   ownerdata = SCIPexprGetOwnerData(expr);
1386 	   assert(ownerdata != NULL);
1387 	   assert(ownerdata->auxvar != NULL);
1388 	
1389 	   if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1390 	   {
1391 	      if( violunder != NULL )
1392 	         *violunder = TRUE;
1393 	      if( violover != NULL )
1394 	         *violover = TRUE;
1395 	      return SCIPinfinity(scip);
1396 	   }
1397 	
1398 	   auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1399 	
1400 	   if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1401 	   {
1402 	      if( violunder != NULL )
1403 	         *violunder = FALSE;
1404 	      if( violover != NULL )
1405 	         *violover = TRUE;
1406 	      return auxvarvalue - SCIPexprGetEvalValue(expr);
1407 	   }
1408 	
1409 	   if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1410 	   {
1411 	      if( violunder != NULL )
1412 	         *violunder = TRUE;
1413 	      if( violover != NULL )
1414 	         *violover = FALSE;
1415 	      return SCIPexprGetEvalValue(expr) - auxvarvalue;
1416 	   }
1417 	
1418 	   if( violunder != NULL )
1419 	      *violunder = FALSE;
1420 	   if( violover != NULL )
1421 	      *violover = FALSE;
1422 	   return 0.0;
1423 	}
1424 	
1425 	/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1426 	 *
1427 	 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1428 	 * Assume that f(w) is associated with auxiliary variable z.
1429 	 *
1430 	 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1431 	 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1432 	 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1433 	 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1434 	 *
1435 	 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1436 	 */
1437 	static
1438 	SCIP_Real getExprAbsAuxViolation(
1439 	   SCIP*                 scip,               /**< SCIP data structure */
1440 	   SCIP_EXPR*            expr,               /**< expression */
1441 	   SCIP_Real             auxvalue,           /**< value of f(w) */
1442 	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
1443 	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(w) is violated, or NULL */
1444 	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(w) is violated, or NULL */
1445 	   )
1446 	{
1447 	   SCIP_EXPR_OWNERDATA* ownerdata;
1448 	   SCIP_Real auxvarvalue;
1449 	
1450 	   assert(expr != NULL);
1451 	
1452 	   ownerdata = SCIPexprGetOwnerData(expr);
1453 	   assert(ownerdata != NULL);
1454 	   assert(ownerdata->auxvar != NULL);
1455 	
1456 	   if( auxvalue == SCIP_INVALID )
1457 	   {
1458 	      if( violunder != NULL )
1459 	         *violunder = TRUE;
1460 	      if( violover != NULL )
1461 	         *violover = TRUE;
1462 	      return SCIPinfinity(scip);
1463 	   }
1464 	
1465 	   auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1466 	
1467 	   if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1468 	   {
1469 	      if( violunder != NULL )
1470 	         *violunder = FALSE;
1471 	      if( violover != NULL )
1472 	         *violover = TRUE;
1473 	      return auxvarvalue - auxvalue;
1474 	   }
1475 	
1476 	   if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1477 	   {
1478 	      if( violunder != NULL )
1479 	         *violunder = TRUE;
1480 	      if( violover != NULL )
1481 	         *violover = FALSE;
1482 	      return auxvalue - auxvarvalue;
1483 	   }
1484 	
1485 	   if( violunder != NULL )
1486 	      *violunder = FALSE;
1487 	   if( violover != NULL )
1488 	      *violover = FALSE;
1489 	
1490 	   return 0.0;
1491 	}
1492 	
1493 	/** computes violation of a constraint */
1494 	static
1495 	SCIP_RETCODE computeViolation(
1496 	   SCIP*                 scip,               /**< SCIP data structure */
1497 	   SCIP_CONS*            cons,               /**< constraint */
1498 	   SCIP_SOL*             sol,                /**< solution or NULL if LP solution should be used */
1499 	   SCIP_Longint          soltag              /**< tag that uniquely identifies the solution (with its values), or 0. */
1500 	   )
1501 	{
1502 	   SCIP_CONSDATA* consdata;
1503 	   SCIP_Real activity;
1504 	
1505 	   assert(scip != NULL);
1506 	   assert(cons != NULL);
1507 	
1508 	   consdata = SCIPconsGetData(cons);
1509 	   assert(consdata != NULL);
1510 	
1511 	   SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1512 	   activity = SCIPexprGetEvalValue(consdata->expr);
1513 	
1514 	   /* consider constraint as violated if it is undefined in the current point */
1515 	   if( activity == SCIP_INVALID )
1516 	   {
1517 	      consdata->lhsviol = SCIPinfinity(scip);
1518 	      consdata->rhsviol = SCIPinfinity(scip);
1519 	      return SCIP_OKAY;
1520 	   }
1521 	
1522 	   /* compute violations */
1523 	   consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs  - activity;
1524 	   consdata->rhsviol = SCIPisInfinity(scip,  consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1525 	
1526 	   return SCIP_OKAY;
1527 	}
1528 	
1529 	/** returns absolute violation of a constraint
1530 	 *
1531 	 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1532 	 */
1533 	static
1534 	SCIP_Real getConsAbsViolation(
1535 	   SCIP_CONS*            cons                /**< constraint */
1536 	   )
1537 	{
1538 	   SCIP_CONSDATA* consdata;
1539 	
1540 	   assert(cons != NULL);
1541 	
1542 	   consdata = SCIPconsGetData(cons);
1543 	   assert(consdata != NULL);
1544 	
1545 	   return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1546 	}
1547 	
1548 	/** computes relative violation of a constraint
1549 	 *
1550 	 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1551 	 */
1552 	static
1553 	SCIP_RETCODE getConsRelViolation(
1554 	   SCIP*                 scip,               /**< SCIP data structure */
1555 	   SCIP_CONS*            cons,               /**< constraint */
1556 	   SCIP_Real*            viol,               /**< buffer to store violation */
1557 	   SCIP_SOL*             sol,                /**< solution or NULL if LP solution should be used */
1558 	   SCIP_Longint          soltag              /**< tag that uniquely identifies the solution (with its values), or 0 */
1559 	   )
1560 	{
1561 	   SCIP_CONSHDLR* conshdlr;
1562 	   SCIP_CONSHDLRDATA* conshdlrdata;
1563 	   SCIP_CONSDATA* consdata;
1564 	   SCIP_Real scale;
1565 	
1566 	   assert(cons != NULL);
1567 	   assert(viol != NULL);
1568 	
1569 	   conshdlr = SCIPconsGetHdlr(cons);
1570 	   assert(conshdlr != NULL);
1571 	
1572 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1573 	   assert(conshdlrdata != NULL);
1574 	
1575 	   *viol = getConsAbsViolation(cons);
1576 	
1577 	   if( conshdlrdata->violscale == 'n' )
1578 	      return SCIP_OKAY;
1579 	
1580 	   if( SCIPisInfinity(scip, *viol) )
1581 	      return SCIP_OKAY;
1582 	
1583 	   consdata = SCIPconsGetData(cons);
1584 	   assert(consdata != NULL);
1585 	
1586 	   if( conshdlrdata->violscale == 'a' )
1587 	   {
1588 	      scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1589 	
1590 	      /* consider value of side that is violated for scaling, too */
1591 	      if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1592 	      {
1593 	         assert(!SCIPisInfinity(scip, -consdata->lhs));
1594 	         scale = REALABS(consdata->lhs);
1595 	      }
1596 	      else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1597 	      {
1598 	         assert(!SCIPisInfinity(scip,  consdata->rhs));
1599 	         scale = REALABS(consdata->rhs);
1600 	      }
1601 	
1602 	      *viol /= scale;
1603 	      return SCIP_OKAY;
1604 	   }
1605 	
1606 	   /* if not 'n' or 'a', then it has to be 'g' at the moment */
1607 	   assert(conshdlrdata->violscale == 'g');
1608 	   if( soltag == 0L || consdata->gradnormsoltag != soltag )
1609 	   {
1610 	      /* we need the varexprs to conveniently access the gradient */
1611 	      SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1612 	
1613 	      /* update cached value of norm of gradient */
1614 	      consdata->gradnorm = 0.0;
1615 	
1616 	      /* compute gradient */
1617 	      SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1618 	
1619 	      /* gradient evaluation error -> no scaling */
1620 	      if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1621 	      {
1622 	         int i;
1623 	         for( i = 0; i < consdata->nvarexprs; ++i )
1624 	         {
1625 	            SCIP_Real deriv;
1626 	
1627 	            assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1628 	            deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1629 	            if( deriv == SCIP_INVALID )
1630 	            {
1631 	               /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1632 	               consdata->gradnorm = 0.0;
1633 	               break;
1634 	            }
1635 	
1636 	            consdata->gradnorm += deriv*deriv;
1637 	         }
1638 	      }
1639 	      consdata->gradnorm = sqrt(consdata->gradnorm);
1640 	      consdata->gradnormsoltag = soltag;
1641 	   }
1642 	
1643 	   *viol /= MAX(1.0, consdata->gradnorm);
1644 	
1645 	   return SCIP_OKAY;
1646 	}
1647 	
1648 	/** returns whether constraint is currently violated
1649 	 *
1650 	 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1651 	 */
1652 	static
1653 	SCIP_Bool isConsViolated(
1654 	   SCIP*                 scip,               /**< SCIP data structure */
1655 	   SCIP_CONS*            cons                /**< constraint */
1656 	   )
1657 	{
1658 	   return getConsAbsViolation(cons) > SCIPfeastol(scip);
1659 	}
1660 	
1661 	/** checks for a linear variable that can be increased or decreased without harming feasibility */
1662 	static
1663 	void findUnlockedLinearVar(
1664 	   SCIP*                 scip,               /**< SCIP data structure */
1665 	   SCIP_CONS*            cons                /**< constraint */
1666 	   )
1667 	{
1668 	   SCIP_CONSDATA* consdata;
1669 	   int poslock;
1670 	   int neglock;
1671 	   int i;
1672 	
1673 	   assert(cons != NULL);
1674 	
1675 	   consdata = SCIPconsGetData(cons);
1676 	   assert(consdata != NULL);
1677 	
1678 	   consdata->linvarincr = NULL;
1679 	   consdata->linvardecr = NULL;
1680 	   consdata->linvarincrcoef = 0.0;
1681 	   consdata->linvardecrcoef = 0.0;
1682 	
1683 	   /* root expression is not a sum -> no unlocked linear variable available */
1684 	   if( !SCIPisExprSum(scip, consdata->expr) )
1685 	      return;
1686 	
1687 	   for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1688 	   {
1689 	      SCIP_EXPR* child;
1690 	
1691 	      child = SCIPexprGetChildren(consdata->expr)[i];
1692 	      assert(child != NULL);
1693 	
1694 	      /* check whether the child is a variable expression */
1695 	      if( SCIPisExprVar(scip, child) )
1696 	      {
1697 	         SCIP_VAR* var = SCIPgetVarExprVar(child);
1698 	         SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1699 	
1700 	         if( coef > 0.0 )
1701 	         {
1702 	            poslock = !SCIPisInfinity(scip,  consdata->rhs) ? 1 : 0;
1703 	            neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1704 	         }
1705 	         else
1706 	         {
1707 	            poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1708 	            neglock = !SCIPisInfinity(scip,  consdata->rhs) ? 1 : 0;
1709 	         }
1710 	         SCIPdebugMsg(scip, "child <%s> locks: %d %d\n", SCIPvarGetName(var), SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL), SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL));
1711 	
1712 	         if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1713 	         {
1714 	            /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1715 	             * if we have already one candidate, then take the one where the loss in the objective function is less
1716 	             */
1717 	            if( (consdata->linvardecr == NULL) ||
1718 	               (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1719 	            {
1720 	               consdata->linvardecr = var;
1721 	               consdata->linvardecrcoef = coef;
1722 	            }
1723 	         }
1724 	
1725 	         if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1726 	         {
1727 	            /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1728 	             * if we have already one candidate, then take the one where the loss in the objective function is less
1729 	             */
1730 	            if( (consdata->linvarincr == NULL) ||
1731 	               (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1732 	            {
1733 	               consdata->linvarincr = var;
1734 	               consdata->linvarincrcoef = coef;
1735 	            }
1736 	         }
1737 	      }
1738 	   }
1739 	
1740 	   assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1741 	   assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1742 	
1743 	   if( consdata->linvarincr != NULL )
1744 	   {
1745 	      SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1746 	   }
1747 	   if( consdata->linvardecr != NULL )
1748 	   {
1749 	      SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1750 	   }
1751 	}
1752 	
1753 	/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1754 	 *  moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1755 	 *
1756 	 *  The method assumes that this is always possible and that not all constraints are feasible already.
1757 	 */
1758 	static
1759 	SCIP_RETCODE proposeFeasibleSolution(
1760 	   SCIP*                 scip,               /**< SCIP data structure */
1761 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1762 	   SCIP_CONS**           conss,              /**< constraints to process */
1763 	   int                   nconss,             /**< number of constraints */
1764 	   SCIP_SOL*             sol,                /**< solution to process */
1765 	   SCIP_Bool*            success             /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1766 	   )
1767 	{
1768 	   SCIP_CONSHDLRDATA* conshdlrdata;
1769 	   SCIP_SOL* newsol;
1770 	   int c;
1771 	
1772 	   assert(scip  != NULL);
1773 	   assert(conshdlr != NULL);
1774 	   assert(conss != NULL || nconss == 0);
1775 	   assert(success != NULL);
1776 	
1777 	   *success = FALSE;
1778 	
1779 	   /* don't propose new solutions if not in presolve or solving */
1780 	   if( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE || SCIPgetStage(scip) >= SCIP_STAGE_SOLVED )
1781 	      return SCIP_OKAY;
1782 	
1783 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1784 	   assert(conshdlrdata != NULL);
1785 	
1786 	   if( sol != NULL )
1787 	   {
1788 	      SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1789 	   }
1790 	   else
1791 	   {
1792 	      SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1793 	   }
1794 	   SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1795 	   SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1796 	      sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1797 	
1798 	   for( c = 0; c < nconss; ++c )
1799 	   {
1800 	      SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
1801 	      SCIP_Real viol = 0.0;
1802 	      SCIP_Real delta;
1803 	      SCIP_Real gap;
1804 	
1805 	      assert(consdata != NULL);
1806 	
1807 	      /* get absolute violation and sign */
1808 	      if( consdata->lhsviol > SCIPfeastol(scip) )
1809 	         viol = consdata->lhsviol; /* lhs - activity */
1810 	      else if( consdata->rhsviol > SCIPfeastol(scip) )
1811 	         viol = -consdata->rhsviol; /* rhs - activity */
1812 	      else
1813 	         continue; /* constraint is satisfied */
1814 	
1815 	      if( consdata->linvarincr != NULL &&
1816 	         ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1817 	      {
1818 	         SCIP_VAR* var = consdata->linvarincr;
1819 	
1820 	         /* compute how much we would like to increase var */
1821 	         delta = viol / consdata->linvarincrcoef;
1822 	         assert(delta > 0.0);
1823 	
1824 	         /* if var has an upper bound, may need to reduce delta */
1825 	         if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1826 	         {
1827 	            gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1828 	            delta = MIN(MAX(0.0, gap), delta);
1829 	         }
1830 	         if( SCIPisPositive(scip, delta) )
1831 	         {
1832 	            /* if variable is integral, round delta up so that it will still have an integer value */
1833 	            if( SCIPvarIsIntegral(var) )
1834 	               delta = SCIPceil(scip, delta);
1835 	
1836 	            SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1837 	            SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1838 	               SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));  /*lint !e613*/
1839 	
1840 	            /* adjust constraint violation, if satisfied go on to next constraint */
1841 	            viol -= consdata->linvarincrcoef * delta;
1842 	            if( SCIPisZero(scip, viol) )
1843 	               continue;
1844 	         }
1845 	      }
1846 	
1847 	      assert(viol != 0.0);
1848 	      if( consdata->linvardecr != NULL &&
1849 	         ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1850 	      {
1851 	         SCIP_VAR* var = consdata->linvardecr;
1852 	
1853 	         /* compute how much we would like to decrease var */
1854 	         delta = viol / consdata->linvardecrcoef;
1855 	         assert(delta < 0.0);
1856 	
1857 	         /* if var has a lower bound, may need to reduce delta */
1858 	         if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
1859 	         {
1860 	            gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1861 	            delta = MAX(MIN(0.0, gap), delta);
1862 	         }
1863 	         if( SCIPisNegative(scip, delta) )
1864 	         {
1865 	            /* if variable is integral, round delta down so that it will still have an integer value */
1866 	            if( SCIPvarIsIntegral(var) )
1867 	               delta = SCIPfloor(scip, delta);
1868 	            SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1869 	            /*lint --e{613} */
1870 	            SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1871 	               SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1872 	
1873 	            /* adjust constraint violation, if satisfied go on to next constraint */
1874 	            viol -= consdata->linvardecrcoef * delta;
1875 	            if( SCIPisZero(scip, viol) )
1876 	               continue;
1877 	         }
1878 	      }
1879 	
1880 	      /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1881 	      break;
1882 	   }
1883 	
1884 	   /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1885 	    * then pass it to the trysol heuristic
1886 	    */
1887 	   if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1888 	   {
1889 	      SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1890 	
1891 	      assert(conshdlrdata->trysolheur != NULL);
1892 	      SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1893 	
1894 	      *success = TRUE;
1895 	   }
1896 	
1897 	   SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1898 	
1899 	   return SCIP_OKAY;
1900 	}
1901 	
1902 	/** adds globally valid tight estimators in a given solution as cut to cutpool
1903 	 *
1904 	 * Called by addTightEstimatorCuts() for a specific expression, nlhdlr, and estimate-direction (over or under).
1905 	 */
1906 	static
1907 	SCIP_RETCODE addTightEstimatorCut(
1908 	   SCIP*                 scip,               /**< SCIP data structure */
1909 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1910 	   SCIP_CONS*            cons,               /**< constraint */
1911 	   SCIP_EXPR*            expr,               /**< expression */
1912 	   EXPRENFO*             exprenfo,           /**< expression enfo data, e.g., nlhdlr to use */
1913 	   SCIP_SOL*             sol,                /**< reference point where to estimate */
1914 	   SCIP_Bool             overestimate,       /**< whether to overestimate */
1915 	   SCIP_PTRARRAY*        rowpreps            /**< array for rowpreps */
1916 	   )
1917 	{
1918 	   SCIP_Bool estimatesuccess = FALSE;
1919 	   SCIP_Bool branchscoresuccess = FALSE;
1920 	   int minidx;
1921 	   int maxidx;
1922 	   int r;
1923 	
1924 	   assert(scip != NULL);
1925 	   assert(expr != NULL);
1926 	   assert(exprenfo != NULL);
1927 	   assert(rowpreps != NULL);
1928 	
1929 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   %sestimate using nlhdlr <%s> for expr %p (%s)\n",
1930 	      overestimate ? "over" : "under", SCIPnlhdlrGetName(exprenfo->nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))); )
1931 	
1932 	   SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, exprenfo->nlhdlr, expr, exprenfo->nlhdlrexprdata, sol,
1933 	      exprenfo->auxvalue, overestimate, SCIPinfinity(scip), FALSE, rowpreps, &estimatesuccess, &branchscoresuccess) );
1934 	
1935 	   minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
1936 	   maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
1937 	   assert(estimatesuccess == (minidx <= maxidx));
1938 	
1939 	   if( !estimatesuccess )
1940 	   {
1941 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s failed\n", SCIPnlhdlrGetName(exprenfo->nlhdlr)); )
1942 	      return SCIP_OKAY;
1943 	   }
1944 	
1945 	   for( r = minidx; r <= maxidx; ++r )
1946 	   {
1947 	      SCIP_ROWPREP* rowprep;
1948 	      SCIP_ROW* row;
1949 	      SCIP_Real estimateval;
1950 	      int i;
1951 	
1952 	      rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
1953 	      assert(rowprep != NULL);
1954 	      assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
1955 	
1956 	      /* if estimators is only local valid, then skip */
1957 	      if( SCIProwprepIsLocal(rowprep) )
1958 	      {
1959 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    skip local estimator\n"); )
1960 	         SCIPfreeRowprep(scip, &rowprep);
1961 	         continue;
1962 	      }
1963 	
1964 	      /* compute value of estimator */
1965 	      estimateval = -SCIProwprepGetSide(rowprep);
1966 	      for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
1967 	         estimateval += SCIProwprepGetCoefs(rowprep)[i] * SCIPgetSolVal(scip, sol, SCIProwprepGetVars(rowprep)[i]);
1968 	
1969 	      /* if estimator value is not tight (or even "more than tight", e.g., when estimating in integer vars), then skip */
1970 	      if( (overestimate && !SCIPisFeasLE(scip, estimateval, SCIPexprGetEvalValue(expr))) ||
1971 	         (!overestimate && !SCIPisFeasGE(scip, estimateval, SCIPexprGetEvalValue(expr))) )
1972 	      {
1973 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    skip non-tight estimator with value %g, expr value %g\n", estimateval, SCIPexprGetEvalValue(expr)); )
1974 	         SCIPfreeRowprep(scip, &rowprep);
1975 	         continue;
1976 	      }
1977 	
1978 	      /* complete estimator to cut and clean it up */
1979 	      SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
1980 	      SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPinfinity(scip), &estimatesuccess) );
1981 	
1982 	      /* if cleanup failed or rowprep is local now, then skip */
1983 	      if( !estimatesuccess || SCIProwprepIsLocal(rowprep) )
1984 	      {
1985 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    skip after cleanup failed or made estimator locally valid\n"); )
1986 	         SCIPfreeRowprep(scip, &rowprep);
1987 	         continue;
1988 	      }
1989 	
1990 	      /* generate row and add to cutpool */
1991 	      SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
1992 	
1993 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    adding cut ");
1994 	      SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
1995 	
1996 	      SCIP_CALL( SCIPaddPoolCut(scip, row) );
1997 	      /* SCIPnlhdlrIncrementNSeparated(nlhdlr); */
1998 	
1999 	      SCIP_CALL( SCIPreleaseRow(scip, &row) );
2000 	      SCIPfreeRowprep(scip, &rowprep);
2001 	   }
2002 	
2003 	   SCIP_CALL( SCIPclearPtrarray(scip, rowpreps) );
2004 	
2005 	   return SCIP_OKAY;
2006 	}
2007 	
2008 	/** adds globally valid tight estimators in a given solution as cuts to cutpool
2009 	 *
2010 	 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
2011 	 * For convex constraints, we would achieve this by linearizing.
2012 	 * To avoid checking explicitly for convexity, we compute estimators via any nlhdlr that didn't say it would
2013 	 * use bound information and check whether the estimator is tight.
2014 	 *
2015 	 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
2016 	 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
2017 	 */
2018 	static
2019 	SCIP_RETCODE addTightEstimatorCuts(
2020 	   SCIP*                 scip,               /**< SCIP data structure */
2021 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2022 	   SCIP_CONS**           conss,              /**< constraints */
2023 	   int                   nconss,             /**< number of constraints */
2024 	   SCIP_SOL*             sol                 /**< reference point where to estimate */
2025 	   )
2026 	{
2027 	   SCIP_CONSDATA* consdata;
2028 	   SCIP_Longint soltag;
2029 	   SCIP_EXPRITER* it;
2030 	   SCIP_EXPR* expr;
2031 	   SCIP_PTRARRAY* rowpreps;
2032 	   int c, e;
2033 	
2034 	   assert(scip != NULL);
2035 	   assert(conshdlr != NULL);
2036 	   assert(conss != NULL || nconss == 0);
2037 	
2038 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "add tight estimators in new solution from <%s> to cutpool\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
2039 	
2040 	   /* TODO probably we just evaluated all expressions when checking the sol before it was added
2041 	    * would be nice to recognize this and skip reevaluating
2042 	    */
2043 	   soltag = SCIPgetExprNewSoltag(scip);
2044 	
2045 	   SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
2046 	
2047 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2048 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
2049 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_LEAVEEXPR);
2050 	
2051 	   for( c = 0; c < nconss; ++c )
2052 	   {
2053 	      /* skip constraints that are not enabled or deleted or have separation disabled */
2054 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2055 	         continue;
2056 	      assert(SCIPconsIsActive(conss[c]));
2057 	
2058 	      consdata = SCIPconsGetData(conss[c]);
2059 	      assert(consdata != NULL);
2060 	
2061 	      /* TODO we could remember for which constraints there is a chance that we would add anything,
2062 	       * i.e., there is some convex-like expression, and skip other constraints
2063 	       */
2064 	
2065 	      ENFOLOG(
2066 	      {
2067 	         int i;
2068 	         SCIPinfoMessage(scip, enfologfile, " constraint ");
2069 	         SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2070 	         SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2071 	         for( i = 0; i < consdata->nvarexprs; ++i )
2072 	         {
2073 	            SCIP_VAR* var;
2074 	            var = SCIPgetVarExprVar(consdata->varexprs[i]);
2075 	            SCIPinfoMessage(scip, enfologfile, "  %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2076 	                  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2077 	         }
2078 	      })
2079 	
2080 	      SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2081 	      assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2082 	
2083 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2084 	      {
2085 	         SCIP_EXPR_OWNERDATA* ownerdata;
2086 	
2087 	         ownerdata = SCIPexprGetOwnerData(expr);
2088 	         assert(ownerdata != NULL);
2089 	
2090 	         /* we can only generate a cut from an estimator if there is an auxvar */
2091 	         if( ownerdata->auxvar == NULL )
2092 	            continue;
2093 	
2094 	         /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2095 	         assert(SCIPexprGetEvalTag(expr) == soltag);
2096 	         assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2097 	         SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2098 	
2099 	         /* generate cuts from estimators of each nonlinear handler that provides estimates */
2100 	         for( e = 0; e < ownerdata->nenfos; ++e )
2101 	         {
2102 	            SCIP_NLHDLR* nlhdlr;
2103 	
2104 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
2105 	            assert(nlhdlr != NULL);
2106 	
2107 	            /* skip nlhdlr that does not implement estimate (so it does enfo) */
2108 	            if( !SCIPnlhdlrHasEstimate(nlhdlr) )
2109 	               continue;
2110 	
2111 	            /* skip nlhdlr that does not participate in separation or looks like it would give only locally-valid estimators
2112 	             * (because it uses activities on vars/auxvars)
2113 	             */
2114 	            if( ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 || ownerdata->enfos[e]->sepaaboveusesactivity) &&
2115 	                ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 || ownerdata->enfos[e]->sepabelowusesactivity) )
2116 	               continue;
2117 	
2118 	            /* skip nlhdlr_default on sum, as the estimator doesn't depend on the reference point (expr is linear in auxvars) */
2119 	            if( SCIPisExprSum(scip, expr) && strcmp(SCIPnlhdlrGetName(nlhdlr), "default") == 0 )
2120 	               continue;
2121 	
2122 	            /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables, since some nlhdlr expect this before their estimate is called */
2123 	            SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
2124 	            ENFOLOG(
2125 	               SCIPinfoMessage(scip, enfologfile, "  expr ");
2126 	               SCIPprintExpr(scip, expr, enfologfile);
2127 	               SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g, nlhdlr <%s> auxvalue: %.15g\n",
2128 	                  (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar), SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
2129 	            )
2130 	            /* due to setting values of auxvars to expr values in sol, the auxvalue should equal to expr evalvalue */
2131 	            assert(SCIPisEQ(scip, ownerdata->enfos[e]->auxvalue, SCIPexprGetEvalValue(expr)));
2132 	
2133 	            /* if nlhdlr wants to be called for overestimate and does not use local bounds, then call estimate of nlhdlr */
2134 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) && !ownerdata->enfos[e]->sepaaboveusesactivity )
2135 	            {
2136 	               SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, TRUE, rowpreps) );
2137 	            }
2138 	
2139 	            /* if nlhdlr wants to be called for underestimate and does not use local bounds, then call estimate of nlhdlr */
2140 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) && !ownerdata->enfos[e]->sepabelowusesactivity )
2141 	            {
2142 	               SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, FALSE, rowpreps) );
2143 	            }
2144 	         }
2145 	      }
2146 	   }
2147 	
2148 	   SCIPfreeExpriter(&it);
2149 	   SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
2150 	
2151 	   return SCIP_OKAY;
2152 	}
2153 	
2154 	/** processes the event that a new primal solution has been found */
2155 	static
2156 	SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2157 	{
2158 	   SCIP_CONSHDLR* conshdlr;
2159 	   SCIP_CONSHDLRDATA* conshdlrdata;
2160 	   SCIP_SOL* sol;
2161 	
2162 	   assert(scip != NULL);
2163 	   assert(event != NULL);
2164 	   assert(eventdata != NULL);
2165 	   assert(eventhdlr != NULL);
2166 	   assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND);
2167 	
2168 	   conshdlr = (SCIP_CONSHDLR*)eventdata;
2169 	
2170 	   if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2171 	      return SCIP_OKAY;
2172 	
2173 	   sol = SCIPeventGetSol(event);
2174 	   assert(sol != NULL);
2175 	
2176 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2177 	   assert(conshdlrdata != NULL);
2178 	
2179 	   /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2180 	    * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2181 	    * from the tree, but postprocessed via proposeFeasibleSolution
2182 	    */
2183 	   if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2184 	      return SCIP_OKAY;
2185 	
2186 	   SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2187 	
2188 	   SCIP_CALL( addTightEstimatorCuts(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol) );
2189 	
2190 	   return SCIP_OKAY;
2191 	}
2192 	
2193 	/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2194 	 *
2195 	 *  The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2196 	 *  tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2197 	 *
2198 	 *  Nothing will happen if SCIP is not in presolve or solve.
2199 	 */
2200 	static
2201 	SCIP_RETCODE tightenAuxVarBounds(
2202 	   SCIP*                 scip,               /**< SCIP data structure */
2203 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2204 	   SCIP_EXPR*            expr,               /**< expression whose auxvar is to be tightened */
2205 	   SCIP_INTERVAL         bounds,             /**< bounds to be used for tightening (must not be empty) */
2206 	   SCIP_Bool*            cutoff,             /**< buffer to store whether a cutoff was detected */
2207 	   int*                  ntightenings        /**< buffer to add the total number of tightenings, or NULL */
2208 	   )
2209 	{
2210 	   SCIP_VAR* var;
2211 	   SCIP_Bool tightenedlb;
2212 	   SCIP_Bool tightenedub;
2213 	   SCIP_Bool force;
2214 	
2215 	   assert(scip != NULL);
2216 	   assert(conshdlr != NULL);
2217 	   assert(expr != NULL);
2218 	   assert(cutoff != NULL);
2219 	
2220 	   /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2221 	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, bounds));
2222 	
2223 	   *cutoff = FALSE;
2224 	
2225 	   /* do not tighten variable in problem stage (important for unittests)
2226 	    * TODO put some kind of #ifdef UNITTEST around this
2227 	    */
2228 	   if( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE && SCIPgetStage(scip) > SCIP_STAGE_SOLVING )
2229 	      return SCIP_OKAY;
2230 	
2231 	   var = SCIPgetExprAuxVarNonlinear(expr);
2232 	   if( var == NULL )
2233 	      return SCIP_OKAY;
2234 	
2235 	   /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2236 	   force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2237 	
2238 	   /* try to tighten lower bound of (auxiliary) variable */
2239 	   SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2240 	   if( tightenedlb )
2241 	   {
2242 	      if( ntightenings != NULL )
2243 	         ++*ntightenings;
2244 	      SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2245 	   }
2246 	   if( *cutoff )
2247 	   {
2248 	      SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2249 	      return SCIP_OKAY;
2250 	   }
2251 	
2252 	   /* try to tighten upper bound of (auxiliary) variable */
2253 	   SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2254 	   if( tightenedub )
2255 	   {
2256 	      if( ntightenings != NULL )
2257 	         ++*ntightenings;
2258 	      SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2259 	   }
2260 	   if( *cutoff )
2261 	   {
2262 	      SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2263 	      return SCIP_OKAY;
2264 	   }
2265 	
2266 	   /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2267 	    * that seems unnecessary and we could easily undo this here, e.g.,
2268 	    * if( tightenedlb ) expr->activity.inf = bounds.inf
2269 	    */
2270 	
2271 	   return SCIP_OKAY;
2272 	}
2273 	
2274 	/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2275 	 *  and tries to tighten the bounds of the auxiliary variables accordingly
2276 	 */
2277 	static
2278 	SCIP_RETCODE forwardPropExpr(
2279 	   SCIP*                 scip,               /**< SCIP data structure */
2280 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2281 	   SCIP_EXPR*            rootexpr,           /**< expression */
2282 	   SCIP_Bool             tightenauxvars,     /**< should the bounds of auxiliary variables be tightened? */
2283 	   SCIP_Bool*            infeasible,         /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2284 	   int*                  ntightenings        /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2285 	   )
2286 	{
2287 	   SCIP_EXPRITER* it;
2288 	   SCIP_EXPR* expr;
2289 	   SCIP_EXPR_OWNERDATA* ownerdata;
2290 	   SCIP_CONSHDLRDATA* conshdlrdata;
2291 	
2292 	   assert(scip != NULL);
2293 	   assert(rootexpr != NULL);
2294 	
2295 	   if( infeasible != NULL )
2296 	      *infeasible = FALSE;
2297 	   if( ntightenings != NULL )
2298 	      *ntightenings = 0;
2299 	
2300 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2301 	   assert(conshdlrdata != NULL);
2302 	
2303 	   /* if value is valid and empty, then we cannot improve, so do nothing */
2304 	   if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2305 	   {
2306 	      SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2307 	
2308 	      if( infeasible != NULL )
2309 	         *infeasible = TRUE;
2310 	
2311 	      /* just update tag to curboundstag */
2312 	      SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2313 	
2314 	      return SCIP_OKAY;
2315 	   }
2316 	
2317 	   /* if value is up-to-date, then nothing to do */
2318 	   if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2319 	   {
2320 	      SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2321 	
2322 	      assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2323 	
2324 	      return SCIP_OKAY;
2325 	   }
2326 	
2327 	   ownerdata = SCIPexprGetOwnerData(rootexpr);
2328 	   assert(ownerdata != NULL);
2329 	
2330 	   /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2331 	    * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2332 	    * during detect, we are in some in-between state where we may want to eval activity
2333 	    * on exprs that we did not notify about their activity usage
2334 	    */
2335 	   if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2336 	   {
2337 	#ifdef DEBUG_PROP
2338 	      SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2339 	#endif
2340 	      SCIPABORT();
2341 	      return SCIP_OKAY;
2342 	   }
2343 	
2344 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2345 	   SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2346 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
2347 	
2348 	   for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it);  )
2349 	   {
2350 	      switch( SCIPexpriterGetStageDFS(it) )
2351 	      {
2352 	         case SCIP_EXPRITER_VISITINGCHILD :
2353 	         {
2354 	            /* skip child if it has been evaluated already */
2355 	            SCIP_EXPR* child;
2356 	
2357 	            child = SCIPexpriterGetChildExprDFS(it);
2358 	            if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2359 	            {
2360 	               if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2361 	                  *infeasible = TRUE;
2362 	
2363 	               expr = SCIPexpriterSkipDFS(it);
2364 	               continue;
2365 	            }
2366 	
2367 	            break;
2368 	         }
2369 	
2370 	         case SCIP_EXPRITER_LEAVEEXPR :
2371 	         {
2372 	            SCIP_INTERVAL activity;
2373 	
2374 	            /* we should not have entered this expression if its activity was already up to date */
2375 	            assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2376 	
2377 	            ownerdata = SCIPexprGetOwnerData(expr);
2378 	            assert(ownerdata != NULL);
2379 	
2380 	            /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2381 	             * so we can assume that the activity is up to date for all these variables
2382 	             * UNLESS we changed the method used to evaluate activity of variable expressions
2383 	             *   or we currently use global bounds (varevents are catched for local bound changes only)
2384 	             */
2385 	            if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2386 	                SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2387 	            {
2388 	#ifndef NDEBUG
2389 	               SCIP_INTERVAL exprhdlrinterval;
2390 	
2391 	               SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2392 	               assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2393 	               assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2394 	#endif
2395 	#ifdef DEBUG_PROP
2396 	               SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2397 	#endif
2398 	               SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2399 	
2400 	               break;
2401 	            }
2402 	
2403 	            if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2404 	            {
2405 	               /* start with entire activity if current one is invalid */
2406 	               SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
2407 	            }
2408 	            else if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)) )
2409 	            {
2410 	               /* If already empty, then don't try to compute even better activity.
2411 	                * If cons_nonlinear were alone, then we should have noted that we are infeasible
2412 	                * so an assert(infeasible == NULL || *infeasible) should work here.
2413 	                * However, after reporting a cutoff due to expr->activity being empty,
2414 	                * SCIP may wander to a different node and call propagation again.
2415 	                * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2416 	                * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2417 	                * we will still have expr->activity being empty, but will have forgotten
2418 	                * that we found infeasibility here before (!2221#note_134120).
2419 	                * Therefore we just set *infeasibility=TRUE here and stop.
2420 	                */
2421 	               if( infeasible != NULL )
2422 	                  *infeasible = TRUE;
2423 	               SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2424 	               break;
2425 	            }
2426 	            else
2427 	            {
2428 	               /* start with current activity, since it is valid */
2429 	               activity = SCIPexprGetActivity(expr);
2430 	            }
2431 	
2432 	            /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2433 	            if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2434 	            {
2435 	#ifdef DEBUG_PROP
2436 	               SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2437 	#endif
2438 	               break;
2439 	            }
2440 	
2441 	#ifdef DEBUG_PROP
2442 	            SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2443 	            SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2444 	            SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2445 	#endif
2446 	
2447 	            /* run interval eval of nonlinear handlers or expression handler */
2448 	            if( ownerdata->nenfos > 0 )
2449 	            {
2450 	               SCIP_NLHDLR* nlhdlr;
2451 	               SCIP_INTERVAL nlhdlrinterval;
2452 	               int e;
2453 	
2454 	               /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2455 	               for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2456 	               {
2457 	                  /* skip nlhdlr if it does not want to participate in activity computation */
2458 	                  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2459 	                     continue;
2460 	
2461 	                  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2462 	                  assert(nlhdlr != NULL);
2463 	
2464 	                  /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2465 	                  if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2466 	                     continue;
2467 	
2468 	                  /* let nlhdlr evaluate current expression */
2469 	                  nlhdlrinterval = activity;
2470 	                  SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2471 	                     &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2472 	#ifdef DEBUG_PROP
2473 	                  SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2474 	#endif
2475 	
2476 	                  /* update activity by intersecting with computed activity */
2477 	                  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2478 	#ifdef DEBUG_PROP
2479 	                  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2480 	#endif
2481 	               }
2482 	            }
2483 	            else
2484 	            {
2485 	               /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2486 	               SCIP_INTERVAL exprhdlrinterval = activity;
2487 	               SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2488 	#ifdef DEBUG_PROP
2489 	               SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2490 	#endif
2491 	
2492 	               /* update expr->activity by intersecting with computed activity */
2493 	               SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2494 	#ifdef DEBUG_PROP
2495 	               SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2496 	#endif
2497 	            }
2498 	
2499 	            /* if expression is integral, then we try to tighten the interval bounds a bit
2500 	             * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2501 	             * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2502 	             * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2503 	             * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2504 	             * (constants should be ok, too)
2505 	             */
2506 	            if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2507 	            {
2508 	               if( activity.inf > -SCIP_INTERVAL_INFINITY )
2509 	                  activity.inf = SCIPceil(scip, activity.inf);
2510 	               if( activity.sup <  SCIP_INTERVAL_INFINITY )
2511 	                  activity.sup = SCIPfloor(scip, activity.sup);
2512 	#ifdef DEBUG_PROP
2513 	               SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2514 	#endif
2515 	            }
2516 	
2517 	            /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2518 	             * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2519 	             */
2520 	            if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2521 	            {
2522 	               SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2523 	               SCIPintervalSetEmpty(&activity);
2524 	            }
2525 	
2526 	            /* now finally store activity in expr */
2527 	            SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2528 	
2529 	            if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity) )
2530 	            {
2531 	               if( infeasible != NULL )
2532 	                  *infeasible = TRUE;
2533 	            }
2534 	            else if( tightenauxvars && ownerdata->auxvar != NULL )
2535 	            {
2536 	               SCIP_Bool tighteninfeasible;
2537 	
2538 	               SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2539 	               if( tighteninfeasible )
2540 	               {
2541 	                  if( infeasible != NULL )
2542 	                     *infeasible = TRUE;
2543 	                  SCIPintervalSetEmpty(&activity);
2544 	                  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2545 	               }
2546 	            }
2547 	
2548 	            break;
2549 	         }
2550 	
2551 	         default:
2552 	            /* you should never be here */
2553 	            SCIPerrorMessage("unexpected iterator stage\n");
2554 	            SCIPABORT();
2555 	            break;
2556 	      }
2557 	
2558 	      expr = SCIPexpriterGetNext(it);
2559 	   }
2560 	
2561 	   SCIPfreeExpriter(&it);
2562 	
2563 	   return SCIP_OKAY;
2564 	}
2565 	
2566 	/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2567 	 *
2568 	 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2569 	 *
2570 	 * If `subsetsufficient` is FALSE, then we require
2571 	 *  - a change from an unbounded interval to a bounded one, or
2572 	 *  - or a change from an unfixed (width > epsilon) to a fixed interval, or
2573 	 *  - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2574 	 */
2575 	static
2576 	SCIP_Bool isIntervalBetter(
2577 	   SCIP*                 scip,               /**< SCIP data structure */
2578 	   SCIP_Bool             subsetsufficient,   /**< whether the intersection being a proper subset of oldinterval is sufficient */
2579 	   SCIP_INTERVAL         newinterval,        /**< new interval */
2580 	   SCIP_INTERVAL         oldinterval         /**< old interval */
2581 	   )
2582 	{
2583 	   assert(scip != NULL);
2584 	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2585 	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2586 	
2587 	   if( subsetsufficient )
2588 	      /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2589 	      return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2590 	
2591 	   /* check whether lower bound of interval becomes finite */
2592 	   if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2593 	      return TRUE;
2594 	
2595 	   /* check whether upper bound of interval becomes finite */
2596 	   if( oldinterval.sup >=  SCIP_INTERVAL_INFINITY && newinterval.sup >  SCIP_INTERVAL_INFINITY )
2597 	      return TRUE;
2598 	
2599 	   /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2600 	   if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2601 	      return TRUE;
2602 	
2603 	   /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2604 	   if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2605 	      return TRUE;
2606 	
2607 	   /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2608 	   if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2609 	      return TRUE;
2610 	
2611 	   return FALSE;
2612 	}
2613 	
2614 	/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2615 	 *
2616 	 *  The expression will be traversed in breadth first search by using this queue.
2617 	 *
2618 	 *  @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2619 	 *  forwardPropExpr() before calling this function.
2620 	 *
2621 	 *  @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2622 	 */
2623 	static
2624 	SCIP_RETCODE reversePropQueue(
2625 	   SCIP*                 scip,               /**< SCIP data structure */
2626 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2627 	   SCIP_Bool*            infeasible,         /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2628 	   int*                  ntightenings        /**< buffer to store the number of (variable) tightenings */
2629 	   )
2630 	{
2631 	   SCIP_CONSHDLRDATA* conshdlrdata;
2632 	   SCIP_EXPR* expr;
2633 	   SCIP_EXPR_OWNERDATA* ownerdata;
2634 	
2635 	   assert(infeasible != NULL);
2636 	   assert(ntightenings != NULL);
2637 	
2638 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2639 	   assert(conshdlrdata != NULL);
2640 	
2641 	   *ntightenings = 0;
2642 	
2643 	   /* main loop that calls reverse propagation for expressions on the queue
2644 	    * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2645 	    */
2646 	   while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2647 	   {
2648 	      SCIP_INTERVAL propbounds;
2649 	      int e;
2650 	
2651 	      expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2652 	      assert(expr != NULL);
2653 	
2654 	      ownerdata = SCIPexprGetOwnerData(expr);
2655 	      assert(ownerdata != NULL);
2656 	
2657 	      assert(ownerdata->inpropqueue);
2658 	      /* mark that the expression is not in the queue anymore */
2659 	      ownerdata->inpropqueue = FALSE;
2660 	
2661 	      /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2662 	       * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2663 	       */
2664 	      assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2665 	      assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2666 	      assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2667 	
2668 	      /* this intersects propbounds with activity and auxvar bounds
2669 	       * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2670 	       * auxvar bounds separately, so disabling this for now
2671 	       */
2672 	#ifdef SCIP_DISABLED_CODE
2673 	      propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2674 	      if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, propbounds) )
2675 	      {
2676 	         *infeasible = TRUE;
2677 	         break;
2678 	      }
2679 	#else
2680 	      propbounds = ownerdata->propbounds;
2681 	#endif
2682 	
2683 	      if( ownerdata->nenfos > 0 )
2684 	      {
2685 	         /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2686 	         for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2687 	         {
2688 	            SCIP_NLHDLR* nlhdlr;
2689 	            int nreds;
2690 	
2691 	            /* skip nlhdlr if it does not want to participate in activity computation */
2692 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2693 	               continue;
2694 	
2695 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
2696 	            assert(nlhdlr != NULL);
2697 	
2698 	            /* call the reverseprop of the nlhdlr */
2699 	#ifdef SCIP_DEBUG
2700 	            SCIPdebugMsg(scip, "call reverse propagation for ");
2701 	            SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2702 	            SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2703 	#endif
2704 	
2705 	            nreds = 0;
2706 	            SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2707 	            assert(nreds >= 0);
2708 	            *ntightenings += nreds;
2709 	         }
2710 	      }
2711 	      else if( SCIPexprhdlrHasReverseProp(SCIPexprGetHdlr(expr)) )
2712 	      {
2713 	         /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2714 	         SCIP_INTERVAL* childrenbounds;
2715 	         int c;
2716 	
2717 	#ifdef SCIP_DEBUG
2718 	         SCIPdebugMsg(scip, "call reverse propagation for ");
2719 	         SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2720 	         SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2721 	#endif
2722 	
2723 	         /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2724 	          * been initialized in detectNlhdlr yet (nenfos < 0)
2725 	          */
2726 	         assert(ownerdata->nenfos < 0);
2727 	
2728 	         SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2729 	         for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2730 	            childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2731 	
2732 	         /* call the reverseprop of the exprhdlr */
2733 	         SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2734 	
2735 	         if( !*infeasible )
2736 	            for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2737 	            {
2738 	               SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2739 	            }
2740 	
2741 	         SCIPfreeBufferArray(scip, &childrenbounds);
2742 	      }
2743 	   }
2744 	
2745 	   /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2746 	   while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2747 	   {
2748 	      expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2749 	      assert(expr != NULL);
2750 	
2751 	      ownerdata = SCIPexprGetOwnerData(expr);
2752 	      assert(ownerdata != NULL);
2753 	
2754 	      /* mark that the expression is not in the queue anymore */
2755 	      ownerdata->inpropqueue = FALSE;
2756 	   }
2757 	
2758 	   return SCIP_OKAY;
2759 	}
2760 	
2761 	/** calls domain propagation for a given set of constraints
2762 	 *
2763 	 *  The algorithm alternates calls of forward and reverse propagation.
2764 	 *  Forward propagation ensures that activity of expressions is up to date.
2765 	 *  Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2766 	 *  [lhs,rhs] interval as starting point.
2767 	 *
2768 	 *  The propagation algorithm works as follows:
2769 	 *   1. apply forward propagation (update activities) for all constraints not marked as propagated
2770 	 *   2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2771 	 *      if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2772 	 *      provide tighter bounds
2773 	 *   3. apply reverse propagation to all collected expressions; don't explore
2774 	 *      sub-expressions which have not changed since the beginning of the propagation loop
2775 	 *   4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2776 	 *
2777 	 *  @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2778 	 *  reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2779 	 *  constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2780 	 *
2781 	 *  TODO should we distinguish between expressions where activity information is used for separation and those where not,
2782 	 *    e.g., try less to propagate on convex constraints?
2783 	 */
2784 	static
2785 	SCIP_RETCODE propConss(
2786 	   SCIP*                 scip,               /**< SCIP data structure */
2787 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2788 	   SCIP_CONS**           conss,              /**< constraints to propagate */
2789 	   int                   nconss,             /**< total number of constraints */
2790 	   SCIP_Bool             force,              /**< force tightening even if below bound strengthening tolerance */
2791 	   SCIP_RESULT*          result,             /**< pointer to store the result */
2792 	   int*                  nchgbds             /**< buffer to add the number of changed bounds */
2793 	   )
2794 	{
2795 	   SCIP_CONSHDLRDATA* conshdlrdata;
2796 	   SCIP_CONSDATA* consdata;
2797 	   SCIP_EXPR_OWNERDATA* ownerdata;
2798 	   SCIP_Bool cutoff = FALSE;
2799 	   SCIP_INTERVAL conssides;
2800 	   int ntightenings;
2801 	   int roundnr;
2802 	   SCIP_EXPRITER* revpropcollectit = NULL;
2803 	   int i;
2804 	
2805 	   assert(scip != NULL);
2806 	   assert(conshdlr != NULL);
2807 	   assert(conss != NULL);
2808 	   assert(nconss >= 0);
2809 	   assert(result != NULL);
2810 	   assert(nchgbds != NULL);
2811 	   assert(*nchgbds >= 0);
2812 	
2813 	   /* no constraints to propagate */
2814 	   if( nconss == 0 )
2815 	   {
2816 	      *result = SCIP_DIDNOTRUN;
2817 	      return SCIP_OKAY;
2818 	   }
2819 	
2820 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2821 	   assert(conshdlrdata != NULL);
2822 	   assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2823 	   assert(!conshdlrdata->globalbounds);
2824 	
2825 	   *result = SCIP_DIDNOTFIND;
2826 	   roundnr = 0;
2827 	
2828 	   /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2829 	   conshdlrdata->forceboundtightening = force;
2830 	
2831 	   /* invalidate all propbounds (probably not needed) */
2832 	   ++conshdlrdata->curpropboundstag;
2833 	
2834 	   /* create iterator that we will use if we need to look at all auxvars */
2835 	   if( conshdlrdata->propauxvars )
2836 	   {
2837 	      SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2838 	   }
2839 	
2840 	   /* main propagation loop */
2841 	   do
2842 	   {
2843 	      SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2844 	
2845 	      assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2846 	
2847 	      /* apply forward propagation (update expression activities)
2848 	       * and add promising root expressions into queue for reversepropagation
2849 	       */
2850 	      for( i = 0; i < nconss; ++i )
2851 	      {
2852 	         consdata = SCIPconsGetData(conss[i]);
2853 	         assert(consdata != NULL);
2854 	
2855 	         /* skip deleted, non-active, or propagation-disabled constraints */
2856 	         if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2857 	            continue;
2858 	
2859 	         /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2860 	          * activity didn't change
2861 	          */
2862 	         if( consdata->ispropagated )
2863 	            continue;
2864 	
2865 	         /* update activities in expression */
2866 	         SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2867 	         SCIPdebugPrintCons(scip, conss[i], NULL);
2868 	
2869 	         ntightenings = 0;
2870 	         SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2871 	         assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2872 	
2873 	         if( cutoff )
2874 	         {
2875 	            SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2876 	            *result = SCIP_CUTOFF;
2877 	            break;
2878 	         }
2879 	
2880 	         ownerdata = SCIPexprGetOwnerData(consdata->expr);
2881 	
2882 	         /* 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 */
2883 	         if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2884 	         {
2885 	            /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2886 	             *   (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2887 	             *   so taking auxvar bounds is enough)
2888 	             */
2889 	            if( ownerdata->auxvar == NULL )
2890 	            {
2891 	               /* relax sides by SCIPepsilon() and handle infinite sides */
2892 	               SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2893 	               SCIP_Real rhs = SCIPisInfinity(scip,  consdata->rhs) ?  SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2894 	               SCIPintervalSetBounds(&conssides, lhs, rhs);
2895 	            }
2896 	            else
2897 	            {
2898 	               conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2899 	            }
2900 	            SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2901 	         }
2902 	         else
2903 	         {
2904 	            /* check whether bounds of any auxvar used in constraint provides a tightening
2905 	             *   (for the root expression, bounds of auxvar are initially set to constraint sides)
2906 	             * but skip exprs that have an auxvar, but do not participate in propagation
2907 	             */
2908 	            SCIP_EXPR* expr;
2909 	
2910 	            assert(revpropcollectit != NULL);
2911 	            SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2912 	            for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2913 	            {
2914 	               ownerdata = SCIPexprGetOwnerData(expr);
2915 	               assert(ownerdata != NULL);
2916 	
2917 	               if( ownerdata->auxvar == NULL )
2918 	                  continue;
2919 	
2920 	               if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2921 	                  continue;
2922 	
2923 	               conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2924 	               SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2925 	            }
2926 	         }
2927 	
2928 	         if( cutoff )
2929 	         {
2930 	            SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2931 	            *result = SCIP_CUTOFF;
2932 	            break;
2933 	         }
2934 	
2935 	         assert(ntightenings >= 0);
2936 	         if( ntightenings > 0 )
2937 	         {
2938 	            *nchgbds += ntightenings;
2939 	            *result = SCIP_REDUCEDDOM;
2940 	         }
2941 	
2942 	         /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2943 	         consdata->ispropagated = TRUE;
2944 	      }
2945 	
2946 	      /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2947 	      SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2948 	      assert(ntightenings >= 0);
2949 	      assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2950 	
2951 	      if( cutoff )
2952 	      {
2953 	         SCIPdebugMsg(scip, " -> cutoff\n");
2954 	         *result = SCIP_CUTOFF;
2955 	         break;
2956 	      }
2957 	
2958 	      if( ntightenings > 0 )
2959 	      {
2960 	         *nchgbds += ntightenings;
2961 	         *result = SCIP_REDUCEDDOM;
2962 	      }
2963 	   }
2964 	   while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2965 	
2966 	   if( conshdlrdata->propauxvars )
2967 	   {
2968 	      SCIPfreeExpriter(&revpropcollectit);
2969 	   }
2970 	
2971 	   conshdlrdata->forceboundtightening = FALSE;
2972 	
2973 	   /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2974 	   ++conshdlrdata->curpropboundstag;
2975 	
2976 	   return SCIP_OKAY;
2977 	}
2978 	
2979 	/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2980 	 *
2981 	 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2982 	 *
2983 	 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2984 	 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2985 	 */
2986 	static
2987 	SCIP_RETCODE propExprDomains(
2988 	   SCIP*                 scip,               /**< SCIP data structure */
2989 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2990 	   SCIP_CONS**           conss,              /**< constraints to propagate */
2991 	   int                   nconss,             /**< total number of constraints */
2992 	   SCIP_RESULT*          result,             /**< pointer to store the result */
2993 	   int*                  nchgbds             /**< buffer to add the number of changed bounds */
2994 	   )
2995 	{
2996 	   SCIP_CONSDATA* consdata;
2997 	   SCIP_EXPRITER* it;
2998 	   SCIP_EXPR* expr;
2999 	   SCIP_EXPR_OWNERDATA* ownerdata;
3000 	   SCIP_Bool cutoff = FALSE;
3001 	   int ntightenings;
3002 	   int c;
3003 	   int e;
3004 	
3005 	   assert(scip != NULL);
3006 	   assert(conshdlr != NULL);
3007 	   assert(conss != NULL);
3008 	   assert(nconss >= 0);
3009 	   assert(result != NULL);
3010 	   assert(nchgbds != NULL);
3011 	   assert(*nchgbds >= 0);
3012 	
3013 	   assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
3014 	   assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
3015 	   assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
3016 	
3017 	   *result = SCIP_DIDNOTFIND;
3018 	
3019 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3020 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
3021 	
3022 	   for( c = 0; c < nconss && !cutoff; ++c )
3023 	   {
3024 	      /* skip deleted, non-active, or propagation-disabled constraints */
3025 	      if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
3026 	         continue;
3027 	
3028 	      consdata = SCIPconsGetData(conss[c]);
3029 	      assert(consdata != NULL);
3030 	
3031 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
3032 	      {
3033 	         ownerdata = SCIPexprGetOwnerData(expr);
3034 	         assert(ownerdata != NULL);
3035 	
3036 	         /* call reverseprop for those nlhdlr that participate in this expr's activity computation
3037 	          * this will propagate the current activity
3038 	          */
3039 	         for( e = 0; e < ownerdata->nenfos; ++e )
3040 	         {
3041 	            SCIP_NLHDLR* nlhdlr;
3042 	            assert(ownerdata->enfos[e] != NULL);
3043 	
3044 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
3045 	            assert(nlhdlr != NULL);
3046 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
3047 	               continue;
3048 	
3049 	            SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
3050 	                  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
3051 	            ntightenings = 0;
3052 	            SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
3053 	                    SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
3054 	
3055 	            if( cutoff )
3056 	            {
3057 	               /* stop everything if we detected infeasibility */
3058 	               SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3059 	               *result = SCIP_CUTOFF;
3060 	               break;
3061 	            }
3062 	
3063 	            assert(ntightenings >= 0);
3064 	            if( ntightenings > 0 )
3065 	            {
3066 	               *nchgbds += ntightenings;
3067 	               *result = SCIP_REDUCEDDOM;
3068 	            }
3069 	         }
3070 	      }
3071 	   }
3072 	
3073 	   /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
3074 	   SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
3075 	   assert(ntightenings >= 0);
3076 	
3077 	   if( cutoff )
3078 	   {
3079 	      SCIPdebugMsg(scip, " -> cutoff\n");
3080 	      *result = SCIP_CUTOFF;
3081 	   }
3082 	   else if( ntightenings > 0 )
3083 	   {
3084 	      *nchgbds += ntightenings;
3085 	      *result = SCIP_REDUCEDDOM;
3086 	   }
3087 	
3088 	   SCIPfreeExpriter(&it);
3089 	
3090 	   /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
3091 	   ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
3092 	
3093 	   return SCIP_OKAY;
3094 	}
3095 	
3096 	/** propagates variable locks through expression and adds locks to variables */
3097 	static
3098 	SCIP_RETCODE propagateLocks(
3099 	   SCIP*                 scip,               /**< SCIP data structure */
3100 	   SCIP_EXPR*            expr,               /**< expression */
3101 	   int                   nlockspos,          /**< number of positive locks */
3102 	   int                   nlocksneg           /**< number of negative locks */
3103 	   )
3104 	{
3105 	   SCIP_EXPR_OWNERDATA* ownerdata;
3106 	   SCIP_EXPRITER* it;
3107 	   SCIP_EXPRITER_USERDATA ituserdata;
3108 	
3109 	   assert(expr != NULL);
3110 	
3111 	   /* if no locks, then nothing to propagate */
3112 	   if( nlockspos == 0 && nlocksneg == 0 )
3113 	      return SCIP_OKAY;
3114 	
3115 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3116 	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
3117 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
3118 	   assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3119 	
3120 	   /* store locks in root node */
3121 	   ituserdata.intvals[0] = nlockspos;
3122 	   ituserdata.intvals[1] = nlocksneg;
3123 	   SCIPexpriterSetCurrentUserData(it, ituserdata);
3124 	
3125 	   while( !SCIPexpriterIsEnd(it) )
3126 	   {
3127 	      /* collect locks */
3128 	      ituserdata = SCIPexpriterGetCurrentUserData(it);
3129 	      nlockspos = ituserdata.intvals[0];
3130 	      nlocksneg = ituserdata.intvals[1];
3131 	
3132 	      ownerdata = SCIPexprGetOwnerData(expr);
3133 	
3134 	      switch( SCIPexpriterGetStageDFS(it) )
3135 	      {
3136 	         case SCIP_EXPRITER_ENTEREXPR:
3137 	         {
3138 	            if( SCIPisExprVar(scip, expr) )
3139 	            {
3140 	               /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3141 	               SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3142 	            }
3143 	
3144 	            /* add locks to expression */
3145 	            ownerdata->nlockspos += nlockspos;
3146 	            ownerdata->nlocksneg += nlocksneg;
3147 	
3148 	            /* add monotonicity information if expression has been locked for the first time */
3149 	            if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3150 	               && SCIPexprhdlrHasMonotonicity(SCIPexprGetHdlr(expr)) )
3151 	            {
3152 	               int i;
3153 	
3154 	               assert(ownerdata->monotonicity == NULL);
3155 	               assert(ownerdata->monotonicitysize == 0);
3156 	
3157 	               SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3158 	               ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3159 	
3160 	               /* store the monotonicity for each child */
3161 	               for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3162 	               {
3163 	                  SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3164 	               }
3165 	            }
3166 	            break;
3167 	         }
3168 	
3169 	         case SCIP_EXPRITER_LEAVEEXPR :
3170 	         {
3171 	            /* remove monotonicity information if expression has been unlocked */
3172 	            if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3173 	            {
3174 	               assert(ownerdata->monotonicitysize > 0);
3175 	               /* keep this assert for checking whether someone changed an expression without updating locks properly */
3176 	               assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3177 	
3178 	               SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3179 	               ownerdata->monotonicitysize = 0;
3180 	            }
3181 	            break;
3182 	         }
3183 	
3184 	         case SCIP_EXPRITER_VISITINGCHILD :
3185 	         {
3186 	            SCIP_MONOTONE monotonicity;
3187 	
3188 	            /* get monotonicity of child */
3189 	            /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3190 	             * SCIPcallExprMonotonicity
3191 	             */
3192 	            monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3193 	
3194 	            /* compute resulting locks of the child expression */
3195 	            switch( monotonicity )
3196 	            {
3197 	               case SCIP_MONOTONE_INC:
3198 	                  ituserdata.intvals[0] = nlockspos;
3199 	                  ituserdata.intvals[1] = nlocksneg;
3200 	                  break;
3201 	               case SCIP_MONOTONE_DEC:
3202 	                  ituserdata.intvals[0] = nlocksneg;
3203 	                  ituserdata.intvals[1] = nlockspos;
3204 	                  break;
3205 	               case SCIP_MONOTONE_UNKNOWN:
3206 	                  ituserdata.intvals[0] = nlockspos + nlocksneg;
3207 	                  ituserdata.intvals[1] = nlockspos + nlocksneg;
3208 	                  break;
3209 	               case SCIP_MONOTONE_CONST:
3210 	                  ituserdata.intvals[0] = 0;
3211 	                  ituserdata.intvals[1] = 0;
3212 	                  break;
3213 	            }
3214 	            /* set locks in child expression */
3215 	            SCIPexpriterSetChildUserData(it, ituserdata);
3216 	
3217 	            break;
3218 	         }
3219 	
3220 	         default :
3221 	            /* you should never be here */
3222 	            SCIPABORT();
3223 	            break;
3224 	      }
3225 	
3226 	      expr = SCIPexpriterGetNext(it);
3227 	   }
3228 	
3229 	   SCIPfreeExpriter(&it);
3230 	
3231 	   return SCIP_OKAY;
3232 	}
3233 	
3234 	/** main function for adding locks to expressions and variables
3235 	 *
3236 	 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3237 	 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3238 	 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3239 	 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3240 	 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3241 	 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3242 	 * which implies that updating the monotonicity information during the next locking of this expression does not
3243 	 * break existing locks.
3244 	 *
3245 	 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3246 	 *       locks from an expression and repropagating them after the structural changes have been applied.
3247 	 *       Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3248 	 *       to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3249 	 */
3250 	static
3251 	SCIP_RETCODE addLocks(
3252 	   SCIP*                 scip,               /**< SCIP data structure */
3253 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
3254 	   int                   nlockspos,          /**< number of positive rounding locks */
3255 	   int                   nlocksneg           /**< number of negative rounding locks */
3256 	   )
3257 	{
3258 	   SCIP_CONSDATA* consdata;
3259 	
3260 	   assert(cons != NULL);
3261 	
3262 	   if( nlockspos == 0 && nlocksneg == 0 )
3263 	      return SCIP_OKAY;
3264 	
3265 	   consdata = SCIPconsGetData(cons);
3266 	   assert(consdata != NULL);
3267 	
3268 	   /* no constraint sides -> nothing to lock */
3269 	   if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3270 	      return SCIP_OKAY;
3271 	
3272 	   /* remember locks */
3273 	   consdata->nlockspos += nlockspos;
3274 	   consdata->nlocksneg += nlocksneg;
3275 	
3276 	   assert(consdata->nlockspos >= 0);
3277 	   assert(consdata->nlocksneg >= 0);
3278 	
3279 	   /* compute locks for lock propagation */
3280 	   if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3281 	   {
3282 	      SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3283 	   }
3284 	   else if( !SCIPisInfinity(scip, consdata->rhs) )
3285 	   {
3286 	      SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3287 	   }
3288 	   else
3289 	   {
3290 	      assert(!SCIPisInfinity(scip, -consdata->lhs));
3291 	      SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3292 	   }
3293 	
3294 	   return SCIP_OKAY;
3295 	}
3296 	
3297 	/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3298 	static
3299 	SCIP_RETCODE createNlRow(
3300 	   SCIP*                 scip,               /**< SCIP data structure */
3301 	   SCIP_CONS*            cons                /**< nonlinear constraint */
3302 	   )
3303 	{
3304 	   SCIP_CONSDATA* consdata;
3305 	
3306 	   assert(scip != NULL);
3307 	   assert(cons != NULL);
3308 	
3309 	   consdata = SCIPconsGetData(cons);
3310 	   assert(consdata != NULL);
3311 	   assert(consdata->expr != NULL);
3312 	
3313 	   if( consdata->nlrow != NULL )
3314 	   {
3315 	      SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3316 	   }
3317 	
3318 	   /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3319 	   SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3320 	         0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3321 	
3322 	   if( SCIPisExprSum(scip, consdata->expr) )
3323 	   {
3324 	      /* if root is a sum, then split into linear and nonlinear terms */
3325 	      SCIP_EXPR* nonlinpart;
3326 	      SCIP_EXPR* child;
3327 	      SCIP_Real* coefs;
3328 	      int i;
3329 	
3330 	      coefs = SCIPgetCoefsExprSum(consdata->expr);
3331 	
3332 	      /* constant term of sum */
3333 	      SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3334 	
3335 	      /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3336 	      SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3337 	
3338 	      for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3339 	      {
3340 	         child = SCIPexprGetChildren(consdata->expr)[i];
3341 	         if( SCIPisExprVar(scip, child) )
3342 	         {
3343 	            /* linear term */
3344 	            SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3345 	         }
3346 	         else
3347 	         {
3348 	            /* nonlinear term */
3349 	            SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3350 	         }
3351 	      }
3352 	
3353 	      if( SCIPexprGetNChildren(nonlinpart) > 0 )
3354 	      {
3355 	         /* add expression to nlrow (this will make a copy) */
3356 	         SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3357 	      }
3358 	      SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3359 	   }
3360 	   else
3361 	   {
3362 	      SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3363 	   }
3364 	
3365 	   return SCIP_OKAY;
3366 	}
3367 	
3368 	/** compares enfodata by enforcement priority of nonlinear handler
3369 	 *
3370 	 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3371 	 */
3372 	static
3373 	SCIP_DECL_SORTPTRCOMP(enfodataCmp)
3374 	{
3375 	   SCIP_NLHDLR* h1;
3376 	   SCIP_NLHDLR* h2;
3377 	
3378 	   assert(elem1 != NULL);
3379 	   assert(elem2 != NULL);
3380 	
3381 	   h1 = ((EXPRENFO*)elem1)->nlhdlr;
3382 	   h2 = ((EXPRENFO*)elem2)->nlhdlr;
3383 	
3384 	   assert(h1 != NULL);
3385 	   assert(h2 != NULL);
3386 	
3387 	   if( SCIPnlhdlrGetEnfoPriority(h1) != SCIPnlhdlrGetEnfoPriority(h2) )
3388 	      return SCIPnlhdlrGetEnfoPriority(h1) - SCIPnlhdlrGetEnfoPriority(h2);
3389 	
3390 	   if( SCIPnlhdlrGetDetectPriority(h1) != SCIPnlhdlrGetDetectPriority(h2) )
3391 	      return SCIPnlhdlrGetDetectPriority(h1) - SCIPnlhdlrGetDetectPriority(h2);
3392 	
3393 	   return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3394 	}
3395 	
3396 	/** install nlhdlrs in one expression */
3397 	static
3398 	SCIP_RETCODE detectNlhdlr(
3399 	   SCIP*                 scip,               /**< SCIP data structure */
3400 	   SCIP_EXPR*            expr,               /**< expression for which to run detection routines */
3401 	   SCIP_CONS*            cons                /**< constraint for which expr == consdata->expr, otherwise NULL */
3402 	   )
3403 	{
3404 	   SCIP_EXPR_OWNERDATA* ownerdata;
3405 	   SCIP_CONSHDLRDATA* conshdlrdata;
3406 	   SCIP_NLHDLR_METHOD enforcemethodsallowed;
3407 	   SCIP_NLHDLR_METHOD enforcemethods;
3408 	   SCIP_NLHDLR_METHOD enforcemethodsnew;
3409 	   SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3410 	   SCIP_NLHDLR_METHOD nlhdlrparticipating;
3411 	   SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3412 	   int enfossize;  /* allocated length of expr->enfos array */
3413 	   int h;
3414 	
3415 	   assert(expr != NULL);
3416 	
3417 	   ownerdata = SCIPexprGetOwnerData(expr);
3418 	   assert(ownerdata != NULL);
3419 	
3420 	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3421 	   assert(conshdlrdata != NULL);
3422 	   assert(conshdlrdata->auxvarid >= 0);
3423 	   assert(!conshdlrdata->indetect);
3424 	
3425 	   /* there should be no enforcer yet and detection should not even have considered expr yet */
3426 	   assert(ownerdata->nenfos < 0);
3427 	   assert(ownerdata->enfos == NULL);
3428 	
3429 	   /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3430 	    * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3431 	    * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3432 	    * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3433 	    * - if no one uses activity, then do not need activity methods
3434 	    */
3435 	   enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3436 	   if( ownerdata->nauxvaruses == 0 )
3437 	      enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3438 	   else
3439 	   {
3440 	      if( ownerdata->nlockspos == 0 )  /* no need for underestimation */
3441 	         enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3442 	      if( ownerdata->nlocksneg == 0 )  /* no need for overestimation */
3443 	         enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3444 	   }
3445 	   if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3446 	      enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3447 	
3448 	   /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3449 	   assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3450 	
3451 	   /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3452 	   enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3453 	
3454 	   ownerdata->nenfos = 0;
3455 	   enfossize = 2;
3456 	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3457 	   conshdlrdata->indetect = TRUE;
3458 	
3459 	   SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3460 	      cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3461 	      (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3462 	      (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3463 	      (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3464 	
3465 	   for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3466 	   {
3467 	      SCIP_NLHDLR* nlhdlr;
3468 	
3469 	      nlhdlr = conshdlrdata->nlhdlrs[h];
3470 	      assert(nlhdlr != NULL);
3471 	
3472 	      /* skip disabled nlhdlrs */
3473 	      if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3474 	         continue;
3475 	
3476 	      /* call detect routine of nlhdlr */
3477 	      nlhdlrexprdata = NULL;
3478 	      enforcemethodsnew = enforcemethods;
3479 	      nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3480 	      conshdlrdata->registerusesactivitysepabelow = FALSE;  /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3481 	      conshdlrdata->registerusesactivitysepaabove = FALSE;  /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3482 	      SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3483 	
3484 	      /* nlhdlr might have claimed more than needed: clean up sepa flags */
3485 	      nlhdlrparticipating &= enforcemethodsallowed;
3486 	
3487 	      /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3488 	      assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3489 	
3490 	      /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3491 	       * They are also cleaned up here to ensure that only the needed methods are claimed.
3492 	       */
3493 	      nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3494 	
3495 	      /* nlhdlr needs to participate for the methods it is enforcing */
3496 	      assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3497 	
3498 	      if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3499 	      {
3500 	         /* nlhdlr might not have detected anything, or all set flags might have been removed by
3501 	          * clean up; in the latter case, we may need to free nlhdlrexprdata */
3502 	
3503 	         /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3504 	         if( nlhdlrexprdata != NULL )
3505 	         {
3506 	            SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3507 	         }
3508 	         /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3509 	         assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3510 	
3511 	         SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3512 	
3513 	         continue;
3514 	      }
3515 	
3516 	      SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3517 	         SCIPnlhdlrGetName(nlhdlr),
3518 	         ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3519 	         ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3520 	         ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3521 	
3522 	      /* store nlhdlr and its data */
3523 	      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3524 	      SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3525 	      ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3526 	      ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3527 	      ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3528 	      ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3529 	      ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3530 	      ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3531 	      ownerdata->nenfos++;
3532 	
3533 	      /* update enforcement flags */
3534 	      enforcemethods = enforcemethodsnew;
3535 	   }
3536 	
3537 	   conshdlrdata->indetect = FALSE;
3538 	
3539 	   /* stop if an enforcement method is missing but we are already in solving stage
3540 	    * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3541 	    */
3542 	   if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3543 	   {
3544 	      SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3545 	      return SCIP_ERROR;
3546 	   }
3547 	
3548 	   assert(ownerdata->nenfos > 0);
3549 	
3550 	   /* sort nonlinear handlers by enforcement priority, in decreasing order */
3551 	   if( ownerdata->nenfos > 1 )
3552 	      SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3553 	
3554 	   /* resize enfos array to be nenfos long */
3555 	   SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3556 	
3557 	   return SCIP_OKAY;
3558 	}
3559 	
3560 	/** detect nlhdlrs that can handle the expressions */
3561 	static
3562 	SCIP_RETCODE detectNlhdlrs(
3563 	   SCIP*                 scip,               /**< SCIP data structure */
3564 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3565 	   SCIP_CONS**           conss,              /**< constraints for which to run nlhdlr detect */
3566 	   int                   nconss              /**< total number of constraints */
3567 	   )
3568 	{
3569 	   SCIP_CONSHDLRDATA* conshdlrdata;
3570 	   SCIP_CONSDATA* consdata;
3571 	   SCIP_EXPR* expr;
3572 	   SCIP_EXPR_OWNERDATA* ownerdata;
3573 	   SCIP_EXPRITER* it;
3574 	   int i;
3575 	
3576 	   assert(conss != NULL || nconss == 0);
3577 	   assert(nconss >= 0);
3578 	   assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING || SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING);  /* should only be called in presolve or initsolve or consactive */
3579 	
3580 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
3581 	   assert(conshdlrdata != NULL);
3582 	
3583 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3584 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, TRUE) );
3585 	
3586 	   if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3587 	   {
3588 	      /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3589 	       * for example, this happens if globally valid nonlinear constraints are added during the tree search
3590 	       */
3591 	      SCIPincrementCurBoundsTagNonlinear(conshdlr, TRUE);
3592 	      conshdlrdata->globalbounds = TRUE;
3593 	      conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3594 	   }
3595 	
3596 	   for( i = 0; i < nconss; ++i )
3597 	   {
3598 	      assert(conss != NULL && conss[i] != NULL);
3599 	
3600 	      consdata = SCIPconsGetData(conss[i]);
3601 	      assert(consdata != NULL);
3602 	      assert(consdata->expr != NULL);
3603 	
3604 	      /* if a constraint is separated, we currently need it to be initial, too
3605 	       * this is because INITLP will create the auxiliary variables that are used for any separation
3606 	       * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3607 	       */
3608 	      assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3609 	
3610 	      ownerdata = SCIPexprGetOwnerData(consdata->expr);
3611 	      assert(ownerdata != NULL);
3612 	
3613 	      /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3614 	       * then we would normally skip to run DETECT again
3615 	       * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3616 	       * thus, if expr is the root expression, we rerun DETECT
3617 	       */
3618 	      if( ownerdata->nenfos > 0 )
3619 	      {
3620 	         SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3621 	         assert(ownerdata->nenfos < 0);
3622 	      }
3623 	
3624 	      /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3625 	       *   this way we can treat the root expression like any other expression when enforcing via separation
3626 	       * if constraint will be propagated, then register activity usage of root expression
3627 	       * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3628 	       */
3629 	      conshdlrdata->indetect = TRUE;
3630 	      SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, consdata->expr,
3631 	         SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3632 	         SCIPconsIsPropagated(conss[i]),
3633 	         FALSE, FALSE) );
3634 	      conshdlrdata->indetect = FALSE;
3635 	
3636 	      /* compute integrality information for all subexpressions */
3637 	      SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3638 	
3639 	      /* run detectNlhdlr on all expr where required */
3640 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3641 	      {
3642 	         ownerdata = SCIPexprGetOwnerData(expr);
3643 	         assert(ownerdata != NULL);
3644 	
3645 	         /* skip exprs that we already looked at */
3646 	         if( ownerdata->nenfos >= 0 )
3647 	            continue;
3648 	
3649 	         /* if there is use of the auxvar, then someone requires that
3650 	          *   auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3651 	          *   thus, we need to find nlhdlrs that separate or estimate
3652 	          * if there is use of the activity, then there is someone requiring that
3653 	          *   activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3654 	          *   thus, we need to find nlhdlrs that do interval-evaluation
3655 	          */
3656 	         if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3657 	         {
3658 	            SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3659 	
3660 	            assert(ownerdata->nenfos >= 0);
3661 	         }
3662 	         else
3663 	         {
3664 	            /* remember that we looked at this expression during detectNlhdlrs
3665 	             * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3666 	             * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3667 	             * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3668 	             */
3669 	            ownerdata->nenfos = 0;
3670 	         }
3671 	      }
3672 	
3673 	      /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3674 	      if( SCIPconsIsPropagated(conss[i]) )
3675 	         consdata->ispropagated = FALSE;
3676 	   }
3677 	
3678 	   if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3679 	   {
3680 	      /* ensure that the local bounds are used again when reevaluating the expressions later;
3681 	       * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3682 	       */
3683 	      SCIPincrementCurBoundsTagNonlinear(conshdlr, FALSE);
3684 	      conshdlrdata->globalbounds = FALSE;
3685 	      conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3686 	   }
3687 	   else
3688 	   {
3689 	      /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3690 	      SCIPincrementCurBoundsTagNonlinear(conshdlr, FALSE);
3691 	   }
3692 	
3693 	   SCIPfreeExpriter(&it);
3694 	
3695 	   return SCIP_OKAY;
3696 	}
3697 	
3698 	/** initializes (pre)solving data of constraints
3699 	 *
3700 	 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3701 	 * not be modified.
3702 	 * In particular, this function
3703 	 * - runs the detection method of nlhldrs
3704 	 * - looks for unlocked linear variables
3705 	 * - checks curvature (if not in presolve)
3706 	 * - creates and add row to NLP (if not in presolve)
3707 	 *
3708 	 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3709 	 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3710 	 */
3711 	static
3712 	SCIP_RETCODE initSolve(
3713 	   SCIP*                 scip,               /**< SCIP data structure */
3714 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3715 	   SCIP_CONS**           conss,              /**< constraints */
3716 	   int                   nconss              /**< number of constraints */
3717 	   )
3718 	{
3719 	   int c;
3720 	
3721 	   for( c = 0; c < nconss; ++c )
3722 	   {
3723 	      /* check for a linear variable that can be increase or decreased without harming feasibility */
3724 	      findUnlockedLinearVar(scip, conss[c]);
3725 	
3726 	      if( SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3727 	      {
3728 	         SCIP_CONSDATA* consdata;
3729 	         SCIP_Bool success = FALSE;
3730 	
3731 	         consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
3732 	         assert(consdata != NULL);
3733 	         assert(consdata->expr != NULL);
3734 	
3735 	         if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3736 	         {
3737 	            /* call the curvature detection algorithm of the convex nonlinear handler
3738 	             * Check only for those curvature that may result in a convex inequality, i.e.,
3739 	             * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3740 	             * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3741 	             */
3742 	            if( !SCIPisInfinity(scip, -consdata->lhs) )
3743 	            {
3744 	               SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3745 	               if( success )
3746 	                  consdata->curv = SCIP_EXPRCURV_CONCAVE;
3747 	            }
3748 	            if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3749 	            {
3750 	               SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3751 	               if( success )
3752 	                  consdata->curv = SCIP_EXPRCURV_CONVEX;
3753 	            }
3754 	         }
3755 	         else
3756 	         {
3757 	            if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3758 	            {
3759 	               SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3760 	               consdata->curv = SCIP_EXPRCURV_LINEAR;
3761 	            }
3762 	            else
3763 	            {
3764 	               consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3765 	            }
3766 	         }
3767 	         SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3768 	
3769 	         /* add nlrow representation to NLP, if NLP had been constructed */
3770 	         if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3771 	         {
3772 	            if( consdata->nlrow == NULL )
3773 	            {
3774 	               SCIP_CALL( createNlRow(scip, conss[c]) );
3775 	               assert(consdata->nlrow != NULL);
3776 	            }
3777 	            SCIPnlrowSetCurvature(consdata->nlrow, consdata->curv);
3778 	            SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3779 	         }
3780 	      }
3781 	   }
3782 	
3783 	   /* register non linear handlers */
3784 	   SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3785 	
3786 	   return SCIP_OKAY;
3787 	}
3788 	
3789 	/** deinitializes (pre)solving data of constraints
3790 	 *
3791 	 * This removes the initialization data created in initSolve().
3792 	 *
3793 	 * This function can be called in presolve and solve.
3794 	 *
3795 	 * TODO At the moment, it should not be called for a constraint if there are other constraints
3796 	 * that use the same expressions but still require their nlhdlr.
3797 	 * We should probably only decrement the auxvar and activity usage for the root expr and then
3798 	 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3799 	 */
3800 	static
3801 	SCIP_RETCODE deinitSolve(
3802 	   SCIP*                 scip,               /**< SCIP data structure */
3803 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3804 	   SCIP_CONS**           conss,              /**< constraints */
3805 	   int                   nconss              /**< number of constraints */
3806 	   )
3807 	{
3808 	   SCIP_EXPRITER* it;
3809 	   SCIP_EXPR* expr;
3810 	   SCIP_CONSDATA* consdata;
3811 	   SCIP_Bool rootactivityvalid;
3812 	   int c;
3813 	
3814 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3815 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
3816 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_LEAVEEXPR);
3817 	
3818 	   /* call deinitialization callbacks of expression and nonlinear handlers
3819 	    * free nonlinear handlers information from expressions
3820 	    * remove auxiliary variables and nactivityuses counts from expressions
3821 	    */
3822 	   for( c = 0; c < nconss; ++c )
3823 	   {
3824 	      assert(conss != NULL);
3825 	      assert(conss[c] != NULL);
3826 	
3827 	      consdata = SCIPconsGetData(conss[c]);
3828 	      assert(consdata != NULL);
3829 	      assert(consdata->expr != NULL);
3830 	
3831 	      /* check and remember whether activity in root is valid */
3832 	      rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3833 	
3834 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3835 	      {
3836 	         SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3837 	
3838 	         /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3839 	         SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3840 	
3841 	         /* remove quadratic info */
3842 	         SCIPfreeExprQuadratic(scip, expr);
3843 	
3844 	         if( rootactivityvalid )
3845 	         {
3846 	            /* ensure activity is valid if consdata->expr activity is valid
3847 	             * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3848 	             * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3849 	             * so this childs activity would be invalid, which can generate confusion
3850 	             */
3851 	            SCIP_CALL( SCIPevalExprActivity(scip, expr) );
3852 	         }
3853 	      }
3854 	
3855 	      if( consdata->nlrow != NULL )
3856 	      {
3857 	         /* remove row from NLP, if still in solving
3858 	          * if we are in exitsolve, the whole NLP will be freed anyway
3859 	          */
3860 	         if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3861 	         {
3862 	            SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3863 	         }
3864 	
3865 	         SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3866 	      }
3867 	
3868 	      /* forget about linear variables that can be increased or decreased without harming feasibility */
3869 	      consdata->linvardecr = NULL;
3870 	      consdata->linvarincr = NULL;
3871 	
3872 	      /* forget about curvature */
3873 	      consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3874 	   }
3875 	
3876 	   SCIPfreeExpriter(&it);
3877 	
3878 	   return SCIP_OKAY;
3879 	}
3880 	
3881 	/** helper method to decide whether a given expression is product of at least two binary variables */
3882 	static
3883 	SCIP_Bool isBinaryProduct(
3884 	   SCIP*                 scip,               /**< SCIP data structure */
3885 	   SCIP_EXPR*            expr                /**< expression */
3886 	   )
3887 	{
3888 	   int i;
3889 	
3890 	   assert(expr != NULL);
3891 	
3892 	   /* check whether the expression is a product */
3893 	   if( !SCIPisExprProduct(scip, expr) )
3894 	      return FALSE;
3895 	
3896 	   /* don't consider products with a coefficient != 1 and products with a single child
3897 	    * simplification will take care of this expression later
3898 	    */
3899 	   if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3900 	      return FALSE;
3901 	
3902 	   for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3903 	   {
3904 	      SCIP_EXPR* child;
3905 	      SCIP_VAR* var;
3906 	      SCIP_Real ub;
3907 	      SCIP_Real lb;
3908 	
3909 	      child = SCIPexprGetChildren(expr)[i];
3910 	      assert(child != NULL);
3911 	
3912 	      if( !SCIPisExprVar(scip, child) )
3913 	         return FALSE;
3914 	
3915 	      var = SCIPgetVarExprVar(child);
3916 	      lb = SCIPvarGetLbLocal(var);
3917 	      ub = SCIPvarGetUbLocal(var);
3918 	
3919 	      /* check whether variable is integer and has [0,1] as variable bounds */
3920 	      if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3921 	         return FALSE;
3922 	   }
3923 	
3924 	   return TRUE;
3925 	}
3926 	
3927 	/** helper method to collect all bilinear binary product terms */
3928 	static
3929 	SCIP_RETCODE getBilinearBinaryTerms(
3930 	   SCIP*                 scip,               /**< SCIP data structure */
3931 	   SCIP_EXPR*            sumexpr,            /**< sum expression */
3932 	   SCIP_VAR**            xs,                 /**< array to collect first variable of each bilinear binary product */
3933 	   SCIP_VAR**            ys,                 /**< array to collect second variable of each bilinear binary product */
3934 	   int*                  childidxs,          /**< array to store the index of the child of each stored bilinear binary product */
3935 	   int*                  nterms              /**< pointer to store the total number of bilinear binary terms */
3936 	   )
3937 	{
3938 	   int i;
3939 	
3940 	   assert(sumexpr != NULL);
3941 	   assert(SCIPisExprSum(scip, sumexpr));
3942 	   assert(xs != NULL);
3943 	   assert(ys != NULL);
3944 	   assert(childidxs != NULL);
3945 	   assert(nterms != NULL);
3946 	
3947 	   *nterms = 0;
3948 	
3949 	   for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3950 	   {
3951 	      SCIP_EXPR* child;
3952 	
3953 	      child = SCIPexprGetChildren(sumexpr)[i];
3954 	      assert(child != NULL);
3955 	
3956 	      if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3957 	      {
3958 	         SCIP_VAR* x = SCIPgetVarExprVar(SCIPexprGetChildren(child)[0]);
3959 	         SCIP_VAR* y = SCIPgetVarExprVar(SCIPexprGetChildren(child)[1]);
3960 	
3961 	         assert(x != NULL);
3962 	         assert(y != NULL);
3963 	
3964 	         if( x != y )
3965 	         {
3966 	            xs[*nterms] = x;
3967 	            ys[*nterms] = y;
3968 	            childidxs[*nterms] = i;
3969 	            ++(*nterms);
3970 	         }
3971 	      }
3972 	   }
3973 	
3974 	   return SCIP_OKAY;
3975 	}
3976 	
3977 	/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3978 	static
3979 	SCIP_RETCODE reformulateFactorizedBinaryQuadratic(
3980 	   SCIP*                 scip,               /**< SCIP data structure */
3981 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3982 	   SCIP_CONS*            cons,               /**< constraint */
3983 	   SCIP_VAR*             facvar,             /**< variable that has been factorized */
3984 	   SCIP_VAR**            vars,               /**< variables of sum_j c_ij x_j */
3985 	   SCIP_Real*            coefs,              /**< coefficients of sum_j c_ij x_j */
3986 	   int                   nvars,              /**< total number of variables in sum_j c_ij x_j */
3987 	   SCIP_EXPR**           newexpr,            /**< pointer to store the new expression */
3988 	   int*                  naddconss           /**< pointer to update the total number of added constraints (might be NULL) */
3989 	   )
3990 	{
3991 	   SCIP_VAR* auxvar;
3992 	   SCIP_CONS* newcons;
3993 	   SCIP_Real minact = 0.0;
3994 	   SCIP_Real maxact = 0.0;
3995 	   SCIP_Bool integral = TRUE;
3996 	   char name [SCIP_MAXSTRLEN];
3997 	   int i;
3998 	
3999 	   assert(facvar != NULL);
4000 	   assert(vars != NULL);
4001 	   assert(nvars > 1);
4002 	   assert(newexpr != NULL);
4003 	
4004 	   /* compute minimum and maximum activity of sum_j c_ij x_j */
4005 	   /* 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 */
4006 	   for( i = 0; i < nvars; ++i )
4007 	   {
4008 	      minact += MIN(coefs[i], 0.0);
4009 	      maxact += MAX(coefs[i], 0.0);
4010 	      integral = integral && SCIPisIntegral(scip, coefs[i]);
4011 	   }
4012 	   assert(minact <= maxact);
4013 	
4014 	   /* create and add auxiliary variable */
4015 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4016 	   SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
4017 	   SCIP_CALL( SCIPaddVar(scip, auxvar) );
4018 	
4019 	   /* create and add z - maxact x <= 0 */
4020 	   if( !SCIPisZero(scip, maxact) )
4021 	   {
4022 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4023 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
4024 	      SCIP_CALL( SCIPaddCons(scip, newcons) );
4025 	      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4026 	      if( naddconss != NULL )
4027 	         ++(*naddconss);
4028 	   }
4029 	
4030 	   /* create and add  0 <= z - minact x */
4031 	   if( !SCIPisZero(scip, minact) )
4032 	   {
4033 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4034 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
4035 	      SCIP_CALL( SCIPaddCons(scip, newcons) );
4036 	      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4037 	      if( naddconss != NULL )
4038 	         ++(*naddconss);
4039 	   }
4040 	
4041 	   /* create and add minact <= sum_j c_j x_j - z + minact x_i */
4042 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4043 	   SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
4044 	   SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4045 	   if( !SCIPisZero(scip, minact) )
4046 	   {
4047 	      SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
4048 	   }
4049 	   SCIP_CALL( SCIPaddCons(scip, newcons) );
4050 	   SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4051 	   if( naddconss != NULL )
4052 	      ++(*naddconss);
4053 	
4054 	   /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4055 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4056 	   SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4057 	   SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4058 	   if( !SCIPisZero(scip, maxact) )
4059 	   {
4060 	      SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4061 	   }
4062 	   SCIP_CALL( SCIPaddCons(scip, newcons) );
4063 	   SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4064 	   if( naddconss != NULL )
4065 	      ++(*naddconss);
4066 	
4067 	   /* create variable expression */
4068 	   SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4069 	
4070 	   /* release auxvar */
4071 	   SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4072 	
4073 	   return SCIP_OKAY;
4074 	}
4075 	
4076 	/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4077 	static
4078 	SCIP_RETCODE getFactorizedBinaryQuadraticExpr(
4079 	   SCIP*                 scip,               /**< SCIP data structure */
4080 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4081 	   SCIP_CONS*            cons,               /**< constraint */
4082 	   SCIP_EXPR*            sumexpr,            /**< expression */
4083 	   int                   minterms,           /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4084 	   SCIP_EXPR**           newexpr,            /**< pointer to store the expression that represents the binary quadratic */
4085 	   int*                  naddconss           /**< pointer to update the total number of added constraints (might be NULL) */
4086 	   )
4087 	{
4088 	   SCIP_EXPR** exprs = NULL;
4089 	   SCIP_VAR** tmpvars = NULL;
4090 	   SCIP_VAR** vars = NULL;
4091 	   SCIP_VAR** xs = NULL;
4092 	   SCIP_VAR** ys = NULL;
4093 	   SCIP_Real* exprcoefs = NULL;
4094 	   SCIP_Real* tmpcoefs = NULL;
4095 	   SCIP_Real* sumcoefs;
4096 	   SCIP_Bool* isused  = NULL;
4097 	   int* childidxs = NULL;
4098 	   int* count = NULL;
4099 	   int nchildren;
4100 	   int nexprs = 0;
4101 	   int nterms;
4102 	   int nvars;
4103 	   int ntotalvars;
4104 	   int i;
4105 	
4106 	   assert(sumexpr != NULL);
4107 	   assert(minterms > 1);
4108 	   assert(newexpr != NULL);
4109 	
4110 	   *newexpr = NULL;
4111 	
4112 	   /* check whether sumexpr is indeed a sum */
4113 	   if( !SCIPisExprSum(scip, sumexpr) )
4114 	      return SCIP_OKAY;
4115 	
4116 	   nchildren = SCIPexprGetNChildren(sumexpr);
4117 	   sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4118 	   nvars = SCIPgetNVars(scip);
4119 	   ntotalvars = SCIPgetNTotalVars(scip);
4120 	
4121 	   /* check whether there are enough terms available */
4122 	   if( nchildren < minterms )
4123 	      return SCIP_OKAY;
4124 	
4125 	   /* allocate memory */
4126 	   SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4127 	   SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4128 	   SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4129 	
4130 	   /* collect all bilinear binary product terms */
4131 	   SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4132 	
4133 	   /* check whether there are enough terms available */
4134 	   if( nterms < minterms )
4135 	      goto TERMINATE;
4136 	
4137 	   /* store how often each variable appears in a bilinear binary product */
4138 	   SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
4139 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4140 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4141 	
4142 	   SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4143 	   SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4144 	   SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4145 	   SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4146 	
4147 	   for( i = 0; i < nterms; ++i )
4148 	   {
4149 	      int xidx;
4150 	      int yidx;
4151 	
4152 	      assert(xs[i] != NULL);
4153 	      assert(ys[i] != NULL);
4154 	
4155 	      xidx = SCIPvarGetIndex(xs[i]);
4156 	      assert(xidx < ntotalvars);
4157 	      yidx = SCIPvarGetIndex(ys[i]);
4158 	      assert(yidx < ntotalvars);
4159 	
4160 	      ++count[xidx];
4161 	      ++count[yidx];
4162 	
4163 	      SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4164 	      SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4165 	   }
4166 	
4167 	   /* sort variables; don't change order of count array because it depends on problem indices */
4168 	   {
4169 	      int* tmpcount;
4170 	
4171 	      SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4172 	      SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4173 	      SCIPfreeBufferArray(scip, &tmpcount);
4174 	   }
4175 	
4176 	   for( i = 0; i < nvars; ++i )
4177 	   {
4178 	      SCIP_VAR* facvar = vars[i];
4179 	      int ntmpvars = 0;
4180 	      int j;
4181 	
4182 	      /* skip candidate if there are not enough terms left */
4183 	      if( count[SCIPvarGetIndex(vars[i])] < minterms )
4184 	         continue;
4185 	
4186 	      SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4187 	
4188 	      /* collect variables for x_i * sum_j c_ij x_j */
4189 	      for( j = 0; j < nterms; ++j )
4190 	      {
4191 	         int childidx = childidxs[j];
4192 	         assert(childidx >= 0 && childidx < nchildren);
4193 	
4194 	         if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4195 	         {
4196 	            SCIP_Real coef;
4197 	            int xidx;
4198 	            int yidx;
4199 	
4200 	            coef = sumcoefs[childidx];
4201 	            assert(coef != 0.0);
4202 	
4203 	            /* collect corresponding variable */
4204 	            tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4205 	            tmpcoefs[ntmpvars] = coef;
4206 	            ++ntmpvars;
4207 	
4208 	            /* update counters */
4209 	            xidx = SCIPvarGetIndex(xs[j]);
4210 	            assert(xidx < ntotalvars);
4211 	            yidx = SCIPvarGetIndex(ys[j]);
4212 	            assert(yidx < ntotalvars);
4213 	            --count[xidx];
4214 	            --count[yidx];
4215 	            assert(count[xidx] >= 0);
4216 	            assert(count[yidx] >= 0);
4217 	
4218 	            /* mark term to be used */
4219 	            isused[childidx] = TRUE;
4220 	         }
4221 	      }
4222 	      assert(ntmpvars >= minterms);
4223 	      assert(SCIPvarGetIndex(facvar) < ntotalvars);
4224 	      assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4225 	
4226 	      /* create required constraints and store the generated expression */
4227 	      SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4228 	      exprcoefs[nexprs] = 1.0;
4229 	      ++nexprs;
4230 	   }
4231 	
4232 	   /* factorization was only successful if at least one expression has been generated */
4233 	   if( nexprs > 0 )
4234 	   {
4235 	      int nexprsold = nexprs;
4236 	
4237 	      /* add all children of the sum that have not been used */
4238 	      for( i = 0; i < nchildren; ++i )
4239 	      {
4240 	         if( !isused[i] )
4241 	         {
4242 	            exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4243 	            exprcoefs[nexprs] = sumcoefs[i];
4244 	            ++nexprs;
4245 	         }
4246 	      }
4247 	
4248 	      /* create a new sum expression */
4249 	      SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4250 	
4251 	      /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4252 	      for( i = 0; i < nexprsold; ++i )
4253 	      {
4254 	         SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4255 	      }
4256 	   }
4257 	
4258 	TERMINATE:
4259 	   /* free memory */
4260 	   SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4261 	   SCIPfreeBufferArrayNull(scip, &tmpvars);
4262 	   SCIPfreeBufferArrayNull(scip, &exprcoefs);
4263 	   SCIPfreeBufferArrayNull(scip, &exprs);
4264 	   SCIPfreeBufferArrayNull(scip, &vars);
4265 	   SCIPfreeBufferArrayNull(scip, &isused);
4266 	   SCIPfreeBufferArrayNull(scip, &count);
4267 	   SCIPfreeBufferArray(scip, &childidxs);
4268 	   SCIPfreeBufferArray(scip, &ys);
4269 	   SCIPfreeBufferArray(scip, &xs);
4270 	
4271 	   return SCIP_OKAY;
4272 	}
4273 	
4274 	/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4275 	static
4276 	SCIP_RETCODE getBinaryProductExprDo(
4277 	   SCIP*                 scip,               /**< SCIP data structure */
4278 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4279 	   SCIP_EXPR*            prodexpr,           /**< product expression */
4280 	   SCIP_EXPR**           newexpr,            /**< pointer to store the expression that represents the product */
4281 	   int*                  naddconss,          /**< pointer to update the total number of added constraints (might be NULL) */
4282 	   SCIP_Bool             empathy4and         /**< whether to use an AND constraint, if possible */
4283 	   )
4284 	{
4285 	   SCIP_VAR** vars;
4286 	   SCIP_CONS* cons;
4287 	   SCIP_Real* coefs;
4288 	   SCIP_VAR* w;
4289 	   char name[SCIP_MAXSTRLEN];
4290 	   int nchildren;
4291 	   int i;
4292 	
4293 	   assert(conshdlr != NULL);
4294 	   assert(prodexpr != NULL);
4295 	   assert(SCIPisExprProduct(scip, prodexpr));
4296 	   assert(newexpr != NULL);
4297 	
4298 	   nchildren = SCIPexprGetNChildren(prodexpr);
4299 	   assert(nchildren >= 2);
4300 	
4301 	   /* memory to store the variables of the variable expressions (+1 for w) */
4302 	   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4303 	   SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4304 	
4305 	   /* prepare the names of the variable and the constraints */
4306 	   (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform");
4307 	   for( i = 0; i < nchildren; ++i )
4308 	   {
4309 	      vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4310 	      coefs[i] = 1.0;
4311 	      assert(vars[i] != NULL);
4312 	      (void) strcat(name, "_");
4313 	      (void) strcat(name, SCIPvarGetName(vars[i]));
4314 	   }
4315 	
4316 	   /* create and add variable */
4317 	   SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4318 	   SCIP_CALL( SCIPaddVar(scip, w) );
4319 	   SCIPdebugMsg(scip, "  created auxiliary variable %s\n", name);
4320 	
4321 	   /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4322 	   if( nchildren == 2 && !empathy4and )
4323 	   {
4324 	      SCIP_VAR* x = vars[0];
4325 	      SCIP_VAR* y = vars[1];
4326 	
4327 	      assert(x != NULL);
4328 	      assert(y != NULL);
4329 	      assert(x != y);
4330 	
4331 	      /* create and add x - w >= 0 */
4332 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4333 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4334 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4335 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4336 	
4337 	      /* create and add y - w >= 0 */
4338 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4339 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4340 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4341 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4342 	
4343 	      /* create and add x + y - w <= 1 */
4344 	      vars[2] = w;
4345 	      coefs[2] = -1.0;
4346 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4347 	      SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4348 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4349 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4350 	
4351 	      /* update number of added constraints */
4352 	      if( naddconss != NULL )
4353 	         *naddconss += 3;
4354 	   }
4355 	   else
4356 	   {
4357 	      /* create, add, and release AND constraint */
4358 	      SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4359 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4360 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4361 	      SCIPdebugMsg(scip, "  create AND constraint\n");
4362 	
4363 	      /* update number of added constraints */
4364 	      if( naddconss != NULL )
4365 	         *naddconss += 1;
4366 	   }
4367 	
4368 	   /* create variable expression */
4369 	   SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4370 	
4371 	   /* release created variable */
4372 	   SCIP_CALL( SCIPreleaseVar(scip, &w) );
4373 	
4374 	   /* free memory */
4375 	   SCIPfreeBufferArray(scip, &coefs);
4376 	   SCIPfreeBufferArray(scip, &vars);
4377 	
4378 	   return SCIP_OKAY;
4379 	}
4380 	
4381 	/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4382 	static
4383 	SCIP_RETCODE getBinaryProductExpr(
4384 	   SCIP*                 scip,               /**< SCIP data structure */
4385 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4386 	   SCIP_HASHMAP*         exprmap,            /**< map to remember generated variables for visited product expressions */
4387 	   SCIP_EXPR*            prodexpr,           /**< product expression */
4388 	   SCIP_EXPR**           newexpr,            /**< pointer to store the expression that represents the product */
4389 	   int*                  naddconss,          /**< pointer to update the total number of added constraints (might be NULL) */
4390 	   int*                  nchgcoefs           /**< pointer to update the total number of changed coefficients (might be NULL) */
4391 	   )
4392 	{
4393 	   SCIP_CONSHDLRDATA* conshdlrdata;
4394 	   int nchildren;
4395 	
4396 	   assert(prodexpr != NULL);
4397 	   assert(newexpr != NULL);
4398 	
4399 	   *newexpr = NULL;
4400 	
4401 	   /* only consider products of binary variables */
4402 	   if( !isBinaryProduct(scip, prodexpr) )
4403 	      return SCIP_OKAY;
4404 	
4405 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4406 	   assert(conshdlrdata != NULL);
4407 	   nchildren = SCIPexprGetNChildren(prodexpr);
4408 	   assert(nchildren >= 2);
4409 	
4410 	   /* check whether there is already an expression that represents the product */
4411 	   if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4412 	   {
4413 	      *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4414 	      assert(*newexpr != NULL);
4415 	
4416 	      /* capture expression */
4417 	      SCIPcaptureExpr(*newexpr);
4418 	   }
4419 	   else
4420 	   {
4421 	      SCIPdebugMsg(scip, "  product expression %p has been considered for the first time\n", (void*)prodexpr);
4422 	
4423 	      if( nchildren == 2 )
4424 	      {
4425 	         SCIP_CLIQUE** xcliques;
4426 	         SCIP_VAR* x;
4427 	         SCIP_VAR* y;
4428 	         SCIP_Bool found_clique = FALSE;
4429 	         int c;
4430 	
4431 	         /* get variables from the product expression */
4432 	         x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4433 	         assert(x != NULL);
4434 	         y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4435 	         assert(y != NULL);
4436 	         assert(x != y);
4437 	
4438 	         /* first try to find a clique containing both variables */
4439 	         xcliques = SCIPvarGetCliques(x, TRUE);
4440 	
4441 	         /* look in cliques containing x */
4442 	         for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4443 	         {
4444 	            if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4445 	            {
4446 	               /* create zero value expression */
4447 	               SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4448 	
4449 	               if( nchgcoefs != NULL )
4450 	                  *nchgcoefs += 1;
4451 	
4452 	               found_clique = TRUE;
4453 	               break;
4454 	            }
4455 	
4456 	            if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4457 	            {
4458 	               /* create variable expression for x */
4459 	               SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4460 	
4461 	               if( nchgcoefs != NULL )
4462 	                  *nchgcoefs += 2;
4463 	
4464 	               found_clique = TRUE;
4465 	               break;
4466 	            }
4467 	         }
4468 	
4469 	         if( !found_clique )
4470 	         {
4471 	            xcliques = SCIPvarGetCliques(x, FALSE);
4472 	
4473 	            /* look in cliques containing complement of x */
4474 	            for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4475 	            {
4476 	               if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4477 	               {
4478 	                  /* create variable expression for y */
4479 	                  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4480 	
4481 	                  if( nchgcoefs != NULL )
4482 	                     *nchgcoefs += 1;
4483 	
4484 	                  found_clique = TRUE;
4485 	                  break;
4486 	               }
4487 	
4488 	               if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4489 	               {
4490 	                  /* create sum expression */
4491 	                  SCIP_EXPR* sum_children[2];
4492 	                  SCIP_Real sum_coefs[2];
4493 	                  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4494 	                  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4495 	                  sum_coefs[0] = 1.0;
4496 	                  sum_coefs[1] = 1.0;
4497 	                  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4498 	
4499 	                  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4500 	                  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4501 	
4502 	                  if( nchgcoefs != NULL )
4503 	                     *nchgcoefs += 3;
4504 	
4505 	                  found_clique = TRUE;
4506 	                  break;
4507 	               }
4508 	            }
4509 	         }
4510 	
4511 	         /* if the variables are not in a clique, do standard linearization */
4512 	         if( !found_clique )
4513 	         {
4514 	            SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4515 	         }
4516 	      }
4517 	      else
4518 	      {
4519 	         /* linearize binary product using an AND constraint because nchildren > 2 */
4520 	         SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4521 	      }
4522 	
4523 	      /* hash variable expression */
4524 	      SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4525 	   }
4526 	
4527 	   return SCIP_OKAY;
4528 	}
4529 	
4530 	/** helper function to replace binary products in a given constraint */
4531 	static
4532 	SCIP_RETCODE replaceBinaryProducts(
4533 	   SCIP*                 scip,               /**< SCIP data structure */
4534 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4535 	   SCIP_CONS*            cons,               /**< constraint */
4536 	   SCIP_HASHMAP*         exprmap,            /**< map to remember generated variables for visited product expressions */
4537 	   SCIP_EXPRITER*        it,                 /**< expression iterator */
4538 	   int*                  naddconss,          /**< pointer to update the total number of added constraints (might be NULL) */
4539 	   int*                  nchgcoefs           /**< pointer to update the total number of changed coefficients (might be NULL) */
4540 	   )
4541 	{
4542 	   SCIP_CONSHDLRDATA* conshdlrdata;
4543 	   SCIP_CONSDATA* consdata;
4544 	   SCIP_EXPR* expr;
4545 	
4546 	   assert(conshdlr != NULL);
4547 	   assert(cons != NULL);
4548 	   assert(exprmap != NULL);
4549 	   assert(it != NULL);
4550 	
4551 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4552 	   assert(conshdlrdata != NULL);
4553 	
4554 	   consdata = SCIPconsGetData(cons);
4555 	   assert(consdata != NULL);
4556 	   assert(consdata->expr != NULL);
4557 	
4558 	   SCIPdebugMsg(scip, "  check constraint %s\n", SCIPconsGetName(cons));
4559 	
4560 	   for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4561 	   {
4562 	      SCIP_EXPR* newexpr = NULL;
4563 	      SCIP_EXPR* childexpr;
4564 	      int childexpridx;
4565 	
4566 	      childexpridx = SCIPexpriterGetChildIdxDFS(it);
4567 	      assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4568 	      childexpr = SCIPexpriterGetChildExprDFS(it);
4569 	      assert(childexpr != NULL);
4570 	
4571 	      /* try to factorize variables in a sum expression that contains several products of binary variables */
4572 	      if( conshdlrdata->reformbinprodsfac > 1 )
4573 	      {
4574 	         SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4575 	      }
4576 	
4577 	      /* try to create an expression that represents a product of binary variables */
4578 	      if( newexpr == NULL )
4579 	      {
4580 	         SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4581 	      }
4582 	
4583 	      if( newexpr != NULL )
4584 	      {
4585 	         assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4586 	
4587 	         /* replace product expression */
4588 	         SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4589 	
4590 	         /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4591 	         SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4592 	
4593 	         /* mark the constraint to not be simplified anymore */
4594 	         consdata->issimplified = FALSE;
4595 	      }
4596 	   }
4597 	
4598 	   return SCIP_OKAY;
4599 	}
4600 	
4601 	/** reformulates products of binary variables during presolving in the following way:
4602 	 *
4603 	 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4604 	 * 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}:
4605 	 * \f[
4606 	 *    z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4607 	 * \f]
4608 	 *
4609 	 * 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$.
4610 	 * These cliques allow for a better reformulation. There are four cases:
4611 	 *
4612 	 *    1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4613 	 *    2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4614 	 *    3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4615 	 *    4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4616 	 *
4617 	 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4618 	 *
4619 	 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4620 	 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4621 	 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4622 	 * Such a lower sum is reformulated with only one extra variable w_i:
4623 	 * \f{align}{
4624 	 *    \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4625 	 *    \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4626 	 *    \text{minact}\, x_i & \leq w_i, \\
4627 	 *    w_i &\leq \text{maxact}\, x_i, \\
4628 	 *    \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4629 	 *    \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4630 	 * \f}
4631 	 * 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
4632 	 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4633 	 * of terms are prioritized.
4634 	 */
4635 	static
4636 	SCIP_RETCODE presolveBinaryProducts(
4637 	   SCIP*                 scip,               /**< SCIP data structure */
4638 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4639 	   SCIP_CONS**           conss,              /**< constraints */
4640 	   int                   nconss,             /**< total number of constraints */
4641 	   int*                  naddconss,          /**< pointer to store the total number of added constraints (might be NULL) */
4642 	   int*                  nchgcoefs           /**< pointer to store the total number of changed coefficients (might be NULL) */
4643 	   )
4644 	{
4645 	   SCIP_CONSHDLRDATA* conshdlrdata;
4646 	   SCIP_HASHMAP* exprmap;
4647 	   SCIP_EXPRITER* it;
4648 	   int c;
4649 	
4650 	   assert(conshdlr != NULL);
4651 	
4652 	   /* no nonlinear constraints or binary variables -> skip */
4653 	   if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4654 	      return SCIP_OKAY;
4655 	   assert(conss != NULL);
4656 	
4657 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4658 	   assert(conshdlrdata != NULL);
4659 	
4660 	   /* create expression hash map */
4661 	   SCIP_CALL( SCIPhashmapCreate(&exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
4662 	
4663 	   /* create expression iterator */
4664 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4665 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4666 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
4667 	
4668 	   SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4669 	
4670 	   for( c = 0; c < nconss; ++c )
4671 	   {
4672 	      SCIP_CONSDATA* consdata;
4673 	      SCIP_EXPR* newexpr = NULL;
4674 	
4675 	      assert(conss[c] != NULL);
4676 	
4677 	      consdata = SCIPconsGetData(conss[c]);
4678 	      assert(consdata != NULL);
4679 	
4680 	      /* try to reformulate the root expression */
4681 	      if( conshdlrdata->reformbinprodsfac > 1 )
4682 	      {
4683 	         SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4684 	      }
4685 	
4686 	      /* release the root node if another expression has been found */
4687 	      if( newexpr != NULL )
4688 	      {
4689 	         SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4690 	         consdata->expr = newexpr;
4691 	
4692 	         /* mark constraint to be not simplified anymore */
4693 	         consdata->issimplified = FALSE;
4694 	      }
4695 	
4696 	      /* replace each product of binary variables separately */
4697 	      SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4698 	   }
4699 	
4700 	   /* free memory */
4701 	   SCIPhashmapFree(&exprmap);
4702 	   SCIPfreeExpriter(&it);
4703 	
4704 	   return SCIP_OKAY;
4705 	}
4706 	
4707 	/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4708 	 *
4709 	 *  Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4710 	 *  Then scale by -1 if
4711 	 *  - \f$n_+ < n_-\f$, or
4712 	 *  - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4713 	 */
4714 	static
4715 	SCIP_RETCODE scaleConsSides(
4716 	   SCIP*                 scip,               /**< SCIP data structure */
4717 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
4718 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
4719 	   SCIP_Bool*            changed             /**< buffer to store if the expression of cons changed */
4720 	   )
4721 	{
4722 	   SCIP_CONSDATA* consdata;
4723 	   int i;
4724 	
4725 	   assert(cons != NULL);
4726 	
4727 	   consdata = SCIPconsGetData(cons);
4728 	   assert(consdata != NULL);
4729 	
4730 	   if( SCIPisExprSum(scip, consdata->expr) )
4731 	   {
4732 	      SCIP_Real* coefs;
4733 	      SCIP_Real constant;
4734 	      int nchildren;
4735 	      int counter = 0;
4736 	
4737 	      coefs = SCIPgetCoefsExprSum(consdata->expr);
4738 	      constant = SCIPgetConstantExprSum(consdata->expr);
4739 	      nchildren = SCIPexprGetNChildren(consdata->expr);
4740 	
4741 	      /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4742 	      if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4743 	      {
4744 	         SCIP_EXPR* expr;
4745 	         expr = consdata->expr;
4746 	
4747 	         consdata->expr = SCIPexprGetChildren(expr)[0];
4748 	         assert(!SCIPisExprSum(scip, consdata->expr));
4749 	
4750 	         SCIPcaptureExpr(consdata->expr);
4751 	
4752 	         SCIPswapReals(&consdata->lhs, &consdata->rhs);
4753 	         consdata->lhs = -consdata->lhs;
4754 	         consdata->rhs = -consdata->rhs;
4755 	
4756 	         SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4757 	         *changed = TRUE;
4758 	         return SCIP_OKAY;
4759 	      }
4760 	
4761 	      /* compute n_+ - n_i */
4762 	      for( i = 0; i < nchildren; ++i )
4763 	         counter += coefs[i] > 0 ? 1 : -1;
4764 	
4765 	      if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4766 	      {
4767 	         SCIP_EXPR* expr;
4768 	         SCIP_Real* newcoefs;
4769 	
4770 	         /* allocate memory */
4771 	         SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4772 	
4773 	         for( i = 0; i < nchildren; ++i )
4774 	            newcoefs[i] = -coefs[i];
4775 	
4776 	         /* create a new sum expression */
4777 	         SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4778 	
4779 	         /* replace expression in constraint data and scale sides */
4780 	         SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4781 	         consdata->expr = expr;
4782 	         SCIPswapReals(&consdata->lhs, &consdata->rhs);
4783 	         consdata->lhs = -consdata->lhs;
4784 	         consdata->rhs = -consdata->rhs;
4785 	
4786 	         /* free memory */
4787 	         SCIPfreeBufferArray(scip, &newcoefs);
4788 	
4789 	         *changed = TRUE;
4790 	      }
4791 	   }
4792 	
4793 	   return SCIP_OKAY;
4794 	}
4795 	
4796 	/** forbid multiaggrations of variables that appear nonlinear in constraints */
4797 	static
4798 	SCIP_RETCODE forbidNonlinearVariablesMultiaggration(
4799 	   SCIP*                 scip,               /**< SCIP data structure */
4800 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4801 	   SCIP_CONS**           conss,              /**< constraints */
4802 	   int                   nconss              /**< number of constraints */
4803 	   )
4804 	{
4805 	   SCIP_EXPRITER* it;
4806 	   SCIP_CONSDATA* consdata;
4807 	   SCIP_EXPR* expr;
4808 	   int c;
4809 	
4810 	   assert(scip != NULL);
4811 	   assert(conshdlr != NULL);
4812 	
4813 	   if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4814 	      return SCIP_OKAY;
4815 	
4816 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4817 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4818 	
4819 	   for( c = 0; c < nconss; ++c )
4820 	   {
4821 	      consdata = SCIPconsGetData(conss[c]);
4822 	      assert(consdata != NULL);
4823 	
4824 	      /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4825 	       *   i.e., skip children of sum that are variables
4826 	       */
4827 	      if( SCIPisExprSum(scip, consdata->expr) )
4828 	      {
4829 	         int i;
4830 	         SCIP_EXPR* child;
4831 	         for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4832 	         {
4833 	            child = SCIPexprGetChildren(consdata->expr)[i];
4834 	
4835 	            /* skip variable expression, as they correspond to a linear term */
4836 	            if( SCIPisExprVar(scip, child) )
4837 	               continue;
4838 	
4839 	            for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4840 	               if( SCIPisExprVar(scip, expr) )
4841 	               {
4842 	                  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPgetVarExprVar(expr)) );
4843 	               }
4844 	         }
4845 	      }
4846 	      else
4847 	      {
4848 	         for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4849 	            if( SCIPisExprVar(scip, expr) )
4850 	            {
4851 	               SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPgetVarExprVar(expr)) );
4852 	            }
4853 	      }
4854 	   }
4855 	
4856 	   SCIPfreeExpriter(&it);
4857 	
4858 	   return SCIP_OKAY;
4859 	}
4860 	
4861 	/** simplifies expressions and replaces common subexpressions for a set of constraints
4862 	 * @todo put the constant to the constraint sides
4863 	 */
4864 	static
4865 	SCIP_RETCODE canonicalizeConstraints(
4866 	   SCIP*                 scip,               /**< SCIP data structure */
4867 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4868 	   SCIP_CONS**           conss,              /**< constraints */
4869 	   int                   nconss,             /**< total number of constraints */
4870 	   SCIP_PRESOLTIMING     presoltiming,       /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4871 	   SCIP_Bool*            infeasible,         /**< buffer to store whether infeasibility has been detected */
4872 	   int*                  ndelconss,          /**< counter to add number of deleted constraints, or NULL */
4873 	   int*                  naddconss,          /**< counter to add number of added constraints, or NULL */
4874 	   int*                  nchgcoefs           /**< counter to add number of changed coefficients, or NULL */
4875 	   )
4876 	{
4877 	   SCIP_CONSHDLRDATA* conshdlrdata;
4878 	   SCIP_CONSDATA* consdata;
4879 	   int* nlockspos;
4880 	   int* nlocksneg;
4881 	   SCIP_Bool havechange;
4882 	   int i;
4883 	
4884 	   assert(scip != NULL);
4885 	   assert(conshdlr != NULL);
4886 	   assert(conss != NULL);
4887 	   assert(nconss > 0);
4888 	   assert(infeasible != NULL);
4889 	
4890 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4891 	   assert(conshdlrdata != NULL);
4892 	
4893 	   /* update number of canonicalize calls */
4894 	   ++(conshdlrdata->ncanonicalizecalls);
4895 	
4896 	   SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4897 	
4898 	   *infeasible = FALSE;
4899 	
4900 	   /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4901 	   havechange = conshdlrdata->ncanonicalizecalls == 1;
4902 	
4903 	   /* free nonlinear handlers information from expressions */  /* TODO can skip this in first presolve round */
4904 	   SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4905 	
4906 	   /* allocate memory for storing locks of each constraint */
4907 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4908 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4909 	
4910 	   /* unlock all constraints */
4911 	   for( i = 0; i < nconss; ++i )
4912 	   {
4913 	      assert(conss[i] != NULL);
4914 	
4915 	      consdata = SCIPconsGetData(conss[i]);
4916 	      assert(consdata != NULL);
4917 	
4918 	      /* remember locks */
4919 	      nlockspos[i] = consdata->nlockspos;
4920 	      nlocksneg[i] = consdata->nlocksneg;
4921 	
4922 	      /* remove locks */
4923 	      SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4924 	      assert(consdata->nlockspos == 0);
4925 	      assert(consdata->nlocksneg == 0);
4926 	   }
4927 	
4928 	#ifndef NDEBUG
4929 	   /* check whether all locks of each expression have been removed */
4930 	   for( i = 0; i < nconss; ++i )
4931 	   {
4932 	      SCIP_EXPR* expr;
4933 	      SCIP_EXPRITER* it;
4934 	
4935 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4936 	
4937 	      consdata = SCIPconsGetData(conss[i]);
4938 	      assert(consdata != NULL);
4939 	
4940 	      SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_RTOPOLOGIC, TRUE) );
4941 	      for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4942 	      {
4943 	         assert(expr != NULL);
4944 	         assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4945 	         assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4946 	      }
4947 	      SCIPfreeExpriter(&it);
4948 	   }
4949 	#endif
4950 	
4951 	   /* reformulate products of binary variables */
4952 	   if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4953 	      && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4954 	   {
4955 	      int tmpnaddconss = 0;
4956 	      int tmpnchgcoefs = 0;
4957 	
4958 	      /* call this function before simplification because expressions might not be simplified after reformulating
4959 	       * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4960 	       */
4961 	      SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4962 	
4963 	      /* update counters */
4964 	      if( naddconss != NULL )
4965 	         *naddconss = tmpnaddconss;
4966 	      if( nchgcoefs != NULL )
4967 	         *nchgcoefs = tmpnchgcoefs;
4968 	
4969 	      /* check whether at least one expression has changed */
4970 	      if( tmpnaddconss + tmpnchgcoefs > 0 )
4971 	         havechange = TRUE;
4972 	   }
4973 	
4974 	   for( i = 0; i < nconss; ++i )
4975 	   {
4976 	      consdata = SCIPconsGetData(conss[i]);
4977 	      assert(consdata != NULL);
4978 	
4979 	      /* call simplify for each expression */
4980 	      if( !consdata->issimplified && consdata->expr != NULL )
4981 	      {
4982 	         SCIP_EXPR* simplified;
4983 	         SCIP_Bool changed;
4984 	
4985 	         changed = FALSE;
4986 	         SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4987 	         consdata->issimplified = TRUE;
4988 	
4989 	         if( changed )
4990 	            havechange = TRUE;
4991 	
4992 	         /* 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").
4993 	          * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4994 	          */
4995 	         if( simplified != consdata->expr )
4996 	         {
4997 	            assert(changed);
4998 	
4999 	            /* release old expression */
5000 	            SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
5001 	
5002 	            /* store simplified expression */
5003 	            consdata->expr = simplified;
5004 	         }
5005 	         else
5006 	         {
5007 	            /* The simplify captures simplified in any case, also if nothing has changed.
5008 	             * Therefore, we have to release it here.
5009 	             */
5010 	            SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
5011 	         }
5012 	
5013 	         if( *infeasible )
5014 	            break;
5015 	
5016 	         /* scale constraint sides */
5017 	         SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
5018 	
5019 	         if( changed )
5020 	            havechange = TRUE;
5021 	
5022 	         /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
5023 	         if( SCIPisExprValue(scip, consdata->expr) )
5024 	         {
5025 	            SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5026 	            if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5027 	                (!SCIPisInfinity(scip,  consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5028 	            {
5029 	               SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5030 	               SCIPdebugPrintCons(scip, conss[i], NULL);
5031 	               *infeasible = TRUE;
5032 	               break;
5033 	            }
5034 	            else
5035 	            {
5036 	               SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5037 	               SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5038 	               if( ndelconss != NULL )
5039 	                  ++*ndelconss;
5040 	               havechange = TRUE;
5041 	            }
5042 	         }
5043 	      }
5044 	   }
5045 	
5046 	   /* replace common subexpressions */
5047 	   if( havechange && !*infeasible )
5048 	   {
5049 	      SCIP_CONS** consssorted;
5050 	      SCIP_EXPR** rootexprs;
5051 	      SCIP_Bool replacedroot;
5052 	
5053 	      SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5054 	      for( i = 0; i < nconss; ++i )
5055 	         rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5056 	
5057 	      SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5058 	
5059 	      /* update pointer to root expr in constraints, if any has changed
5060 	       * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5061 	       */
5062 	      if( replacedroot )
5063 	         for( i = 0; i < nconss; ++i )
5064 	            SCIPconsGetData(conss[i])->expr = rootexprs[i];
5065 	
5066 	      SCIPfreeBufferArray(scip, &rootexprs);
5067 	
5068 	      /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5069 	       * been changed after simplification; now we completely recollect all variable expression and variable events
5070 	       */
5071 	
5072 	      /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5073 	       * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5074 	       */
5075 	      SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5076 	      SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5077 	
5078 	      for( i = nconss-1; i >= 0; --i )
5079 	      {
5080 	         assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5081 	         if( SCIPconsIsDeleted(consssorted[i]) )
5082 	            continue;
5083 	
5084 	         SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5085 	         SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5086 	      }
5087 	      for( i = 0; i < nconss; ++i )
5088 	      {
5089 	         if( SCIPconsIsDeleted(consssorted[i]) )
5090 	            continue;
5091 	
5092 	         SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5093 	         SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5094 	      }
5095 	
5096 	      SCIPfreeBufferArray(scip, &consssorted);
5097 	
5098 	      /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5099 	       * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5100 	       * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5101 	       */
5102 	      SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5103 	   }
5104 	
5105 	   /* restore locks */
5106 	   for( i = 0; i < nconss; ++i )
5107 	   {
5108 	      if( SCIPconsIsDeleted(conss[i]) )
5109 	         continue;
5110 	
5111 	      SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5112 	   }
5113 	
5114 	   /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5115 	    * TODO can we skip this in presoltiming fast?
5116 	    */
5117 	   if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5118 	   {
5119 	      /* reset one of the number of detections counter to count only current presolving round */
5120 	      for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5121 	         SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5122 	
5123 	      SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5124 	   }
5125 	
5126 	   /* free allocated memory */
5127 	   SCIPfreeBufferArray(scip, &nlocksneg);
5128 	   SCIPfreeBufferArray(scip, &nlockspos);
5129 	
5130 	   SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5131 	
5132 	   return SCIP_OKAY;
5133 	}
5134 	
5135 	/** merges constraints that have the same root expression */
5136 	static
5137 	SCIP_RETCODE presolveMergeConss(
5138 	   SCIP*                 scip,               /**< SCIP data structure */
5139 	   SCIP_CONS**           conss,              /**< constraints to process */
5140 	   int                   nconss,             /**< number of constraints */
5141 	   SCIP_Bool*            success             /**< pointer to store whether at least one constraint could be deleted */
5142 	   )
5143 	{
5144 	   SCIP_HASHMAP* expr2cons;
5145 	   SCIP_Bool* updatelocks;
5146 	   int* nlockspos;
5147 	   int* nlocksneg;
5148 	   int c;
5149 	
5150 	   assert(success != NULL);
5151 	
5152 	   *success = FALSE;
5153 	
5154 	   /* not enough constraints available */
5155 	   if( nconss <= 1 )
5156 	      return SCIP_OKAY;
5157 	
5158 	   SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5159 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5160 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5161 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5162 	
5163 	   for( c = 0; c < nconss; ++c )
5164 	   {
5165 	      SCIP_CONSDATA* consdata;
5166 	
5167 	      /* ignore deleted constraints */
5168 	      if( SCIPconsIsDeleted(conss[c]) )
5169 	         continue;
5170 	
5171 	      consdata = SCIPconsGetData(conss[c]);
5172 	      assert(consdata != NULL);
5173 	
5174 	      /* add expression to the hash map if not seen so far */
5175 	      if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5176 	      {
5177 	         SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5178 	      }
5179 	      else
5180 	      {
5181 	         SCIP_CONSDATA* imgconsdata;
5182 	         int idx;
5183 	
5184 	         idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5185 	         assert(idx >= 0 && idx < nconss);
5186 	
5187 	         imgconsdata = SCIPconsGetData(conss[idx]);
5188 	         assert(imgconsdata != NULL);
5189 	         assert(imgconsdata->expr == consdata->expr);
5190 	
5191 	         SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5192 	            SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5193 	
5194 	         /* check whether locks need to be updated */
5195 	         if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5196 	            || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5197 	         {
5198 	            nlockspos[idx] = imgconsdata->nlockspos;
5199 	            nlocksneg[idx] = imgconsdata->nlocksneg;
5200 	            SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5201 	            updatelocks[idx] = TRUE;
5202 	         }
5203 	
5204 	         /* update constraint sides */
5205 	         imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5206 	         imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5207 	
5208 	         /* delete constraint */
5209 	         SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5210 	         *success = TRUE;
5211 	      }
5212 	   }
5213 	
5214 	   /* restore locks of updated constraints */
5215 	   if( *success )
5216 	   {
5217 	      for( c = 0; c < nconss; ++c )
5218 	      {
5219 	         if( updatelocks[c] )
5220 	         {
5221 	            SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5222 	         }
5223 	      }
5224 	   }
5225 	
5226 	   /* free memory */
5227 	   SCIPfreeBufferArray(scip, &nlocksneg);
5228 	   SCIPfreeBufferArray(scip, &nlockspos);
5229 	   SCIPfreeBufferArray(scip, &updatelocks);
5230 	   SCIPhashmapFree(&expr2cons);
5231 	
5232 	   return SCIP_OKAY;
5233 	}
5234 	
5235 	/** interval evaluation of variables as used in redundancy check
5236 	 *
5237 	 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5238 	 */
5239 	static
5240 	SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5241 	{  /*lint --e{715}*/
5242 	   SCIP_CONSHDLRDATA* conshdlrdata;
5243 	   SCIP_INTERVAL interval;
5244 	   SCIP_Real lb;
5245 	   SCIP_Real ub;
5246 	
5247 	   assert(scip != NULL);
5248 	   assert(var != NULL);
5249 	
5250 	   conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5251 	   assert(conshdlrdata != NULL);
5252 	
5253 	   if( conshdlrdata->globalbounds )
5254 	   {
5255 	      lb = SCIPvarGetLbGlobal(var);
5256 	      ub = SCIPvarGetUbGlobal(var);
5257 	   }
5258 	   else
5259 	   {
5260 	      lb = SCIPvarGetLbLocal(var);
5261 	      ub = SCIPvarGetUbLocal(var);
5262 	   }
5263 	   assert(lb <= ub);  /* can SCIP ensure by now that variable bounds are not contradicting? */
5264 	
5265 	   /* relax variable bounds, if there are bounds and variable is not fixed
5266 	    * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5267 	    */
5268 	   if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5269 	   {
5270 	      if( !SCIPisInfinity(scip, -lb) )
5271 	         lb -= SCIPfeastol(scip);
5272 	
5273 	      if( !SCIPisInfinity(scip, ub) )
5274 	         ub += SCIPfeastol(scip);
5275 	   }
5276 	
5277 	   /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5278 	   lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
5279 	   ub =  infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY,  ub);
5280 	   assert(lb <= ub);
5281 	
5282 	   SCIPintervalSetBounds(&interval, lb, ub);
5283 	
5284 	   return interval;
5285 	}
5286 	
5287 	/** removes constraints that are always feasible or very simple
5288 	 *
5289 	 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5290 	 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5291 	 * might violate variable bounds by up to feastol, too.
5292 	 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5293 	 *
5294 	 * Also removes constraints of the form lhs &le; variable &le; rhs.
5295 	 *
5296 	 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5297 	 *
5298 	 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5299 	 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5300 	 * would appear as if the constraint is redundant.
5301 	 */
5302 	static
5303 	SCIP_RETCODE presolveRedundantConss(
5304 	   SCIP*                 scip,               /**< SCIP data structure */
5305 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
5306 	   SCIP_CONS**           conss,              /**< constraints to propagate */
5307 	   int                   nconss,             /**< total number of constraints */
5308 	   SCIP_Bool*            cutoff,             /**< pointer to store whether infeasibility has been identified */
5309 	   int*                  ndelconss,          /**< buffer to add the number of deleted constraints */
5310 	   int*                  nchgbds             /**< buffer to add the number of variable bound tightenings */
5311 	   )
5312 	{
5313 	   SCIP_CONSHDLRDATA* conshdlrdata;
5314 	   SCIP_CONSDATA* consdata;
5315 	   SCIP_INTERVAL activity;
5316 	   SCIP_INTERVAL sides;
5317 	   int i;
5318 	
5319 	   assert(scip != NULL);
5320 	   assert(conshdlr != NULL);
5321 	   assert(conss != NULL);
5322 	   assert(nconss >= 0);
5323 	   assert(cutoff != NULL);
5324 	   assert(ndelconss != NULL);
5325 	   assert(nchgbds != NULL);
5326 	
5327 	   /* no constraints to check */
5328 	   if( nconss == 0 )
5329 	      return SCIP_OKAY;
5330 	
5331 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
5332 	   assert(conshdlrdata != NULL);
5333 	
5334 	   /* increase curboundstag and set lastvaractivitymethodchange
5335 	    * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5336 	    * for the redundancy check differently than for domain propagation
5337 	    * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5338 	    */
5339 	   ++conshdlrdata->curboundstag;
5340 	   assert(conshdlrdata->curboundstag > 0);
5341 	   conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5342 	   conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5343 	   conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5344 	
5345 	   SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5346 	
5347 	   *cutoff = FALSE;
5348 	   for( i = 0; i < nconss; ++i )
5349 	   {
5350 	      if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5351 	         continue;
5352 	
5353 	      consdata = SCIPconsGetData(conss[i]);
5354 	      assert(consdata != NULL);
5355 	
5356 	      /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5357 	      if( SCIPisExprValue(scip, consdata->expr) )
5358 	      {
5359 	         SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5360 	
5361 	         if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5362 	             (!SCIPisInfinity(scip,  consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5363 	         {
5364 	            SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5365 	            *cutoff = TRUE;
5366 	
5367 	            goto TERMINATE;
5368 	         }
5369 	
5370 	         SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5371 	
5372 	         SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5373 	         ++*ndelconss;
5374 	
5375 	         continue;
5376 	      }
5377 	
5378 	      /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5379 	      if( SCIPisExprVar(scip, consdata->expr) )
5380 	      {
5381 	         SCIP_VAR* var;
5382 	         SCIP_Bool tightened;
5383 	
5384 	         var = SCIPgetVarExprVar(consdata->expr);
5385 	         assert(var != NULL);
5386 	
5387 	         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);
5388 	
5389 	         /* ensure that variable bounds are within constraint sides */
5390 	         if( !SCIPisInfinity(scip, -consdata->lhs) )
5391 	         {
5392 	            SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5393 	
5394 	            if( tightened )
5395 	               ++*nchgbds;
5396 	
5397 	            if( *cutoff )
5398 	               goto TERMINATE;
5399 	         }
5400 	
5401 	         if( !SCIPisInfinity(scip, consdata->rhs) )
5402 	         {
5403 	            SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5404 	
5405 	            if( tightened )
5406 	               ++*nchgbds;
5407 	
5408 	            if( *cutoff )
5409 	               goto TERMINATE;
5410 	         }
5411 	
5412 	         /* delete the (now) redundant constraint locally */
5413 	         SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5414 	         ++*ndelconss;
5415 	
5416 	         continue;
5417 	      }
5418 	
5419 	      /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5420 	       * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5421 	       * variable bounds by up to feastol
5422 	       * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5423 	       */
5424 	      SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5425 	      SCIPdebugPrintCons(scip, conss[i], NULL);
5426 	
5427 	      SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5428 	      assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5429 	
5430 	      /* it is unlikely that we detect infeasibility by doing forward propagation */
5431 	      if( *cutoff )
5432 	      {
5433 	         SCIPdebugMsg(scip, " -> cutoff\n");
5434 	         goto TERMINATE;
5435 	      }
5436 	
5437 	      assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5438 	      activity = SCIPexprGetActivity(consdata->expr);
5439 	
5440 	      /* relax sides by feastol
5441 	       * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5442 	       */
5443 	      SCIPintervalSetBounds(&sides,
5444 	         SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5445 	         SCIPisInfinity(scip,  consdata->rhs) ?  SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5446 	
5447 	      if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5448 	      {
5449 	         SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5450 	
5451 	         SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5452 	         ++*ndelconss;
5453 	
5454 	         continue;
5455 	      }
5456 	
5457 	      SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5458 	   }
5459 	
5460 	TERMINATE:
5461 	   /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5462 	   ++conshdlrdata->curboundstag;
5463 	   conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5464 	   conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5465 	   conshdlrdata->intevalvar = intEvalVarBoundTightening;
5466 	
5467 	   return SCIP_OKAY;
5468 	}
5469 	
5470 	/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5471 	static
5472 	SCIP_RETCODE presolveUpgrade(
5473 	   SCIP*                 scip,               /**< SCIP data structure */
5474 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler data structure */
5475 	   SCIP_CONS*            cons,               /**< source constraint to try to convert */
5476 	   SCIP_Bool*            upgraded,           /**< buffer to store whether constraint was upgraded */
5477 	   int*                  nupgdconss,         /**< buffer to increase if constraint was upgraded */
5478 	   int*                  naddconss           /**< buffer to increase with number of additional constraints created during upgrade */
5479 	   )
5480 	{
5481 	   SCIP_CONSHDLRDATA* conshdlrdata;
5482 	   SCIP_CONSDATA* consdata;
5483 	   SCIP_CONS** upgdconss;
5484 	   int upgdconsssize;
5485 	   int nupgdconss_;
5486 	   int i;
5487 	
5488 	   assert(scip != NULL);
5489 	   assert(conshdlr != NULL);
5490 	   assert(cons != NULL);
5491 	   assert(!SCIPconsIsModifiable(cons));
5492 	   assert(upgraded   != NULL);
5493 	   assert(nupgdconss != NULL);
5494 	   assert(naddconss  != NULL);
5495 	
5496 	   *upgraded = FALSE;
5497 	
5498 	   nupgdconss_ = 0;
5499 	
5500 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
5501 	   assert(conshdlrdata != NULL);
5502 	
5503 	   /* if there are no upgrade methods, we can stop */
5504 	   if( conshdlrdata->nconsupgrades == 0 )
5505 	      return SCIP_OKAY;
5506 	
5507 	   upgdconsssize = 2;
5508 	   SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5509 	
5510 	   /* call the upgrading methods */
5511 	   SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5512 	   SCIPdebugPrintCons(scip, cons, NULL);
5513 	
5514 	   consdata = SCIPconsGetData(cons);
5515 	   assert(consdata != NULL);
5516 	
5517 	   /* try all upgrading methods in priority order in case the upgrading step is enable  */
5518 	   for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5519 	   {
5520 	      if( !conshdlrdata->consupgrades[i]->active )
5521 	         continue;
5522 	
5523 	      assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5524 	
5525 	      SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5526 	
5527 	      while( nupgdconss_ < 0 )
5528 	      {
5529 	         /* upgrade function requires more memory: resize upgdconss and call again */
5530 	         assert(-nupgdconss_ > upgdconsssize);
5531 	         upgdconsssize = -nupgdconss_;
5532 	         SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5533 	
5534 	         SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5535 	
5536 	         assert(nupgdconss_ != 0);
5537 	      }
5538 	
5539 	      if( nupgdconss_ > 0 )
5540 	      {
5541 	         /* got upgrade */
5542 	         int j;
5543 	
5544 	         SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5545 	
5546 	         /* add the upgraded constraints to the problem and forget them */
5547 	         for( j = 0; j < nupgdconss_; ++j )
5548 	         {
5549 	            SCIPdebugMsgPrint(scip, "\t");
5550 	            SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5551 	
5552 	            SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) );      /*lint !e613*/
5553 	            SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5554 	         }
5555 	
5556 	         /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5557 	         *nupgdconss += 1;
5558 	         *naddconss += nupgdconss_ - 1;
5559 	         *upgraded = TRUE;
5560 	
5561 	         /* delete upgraded constraint */
5562 	         SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5563 	         SCIP_CALL( SCIPdelCons(scip, cons) );
5564 	
5565 	         break;
5566 	      }
5567 	   }
5568 	
5569 	   SCIPfreeBufferArray(scip, &upgdconss);
5570 	
5571 	   return SCIP_OKAY;
5572 	}
5573 	
5574 	/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5575 	 *  the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5576 	 *  variable bounds, and is not binary
5577 	 */
5578 	static
5579 	SCIP_Bool isSingleLockedCand(
5580 	   SCIP*                 scip,               /**< SCIP data structure */
5581 	   SCIP_EXPR*            expr                /**< variable expression */
5582 	   )
5583 	{
5584 	   SCIP_VAR* var;
5585 	   SCIP_EXPR_OWNERDATA* ownerdata;
5586 	
5587 	   assert(SCIPisExprVar(scip, expr));
5588 	
5589 	   var = SCIPgetVarExprVar(expr);
5590 	   assert(var != NULL);
5591 	
5592 	   ownerdata = SCIPexprGetOwnerData(expr);
5593 	   assert(ownerdata != NULL);
5594 	
5595 	   return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5596 	      && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5597 	      && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5598 	      && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5599 	      && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY
5600 	      && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5601 	}
5602 	
5603 	/** removes all variable expressions that are contained in a given expression from a hash map */
5604 	static
5605 	SCIP_RETCODE removeSingleLockedVars(
5606 	   SCIP*                 scip,               /**< SCIP data structure */
5607 	   SCIP_EXPR*            expr,               /**< expression */
5608 	   SCIP_EXPRITER*        it,                 /**< expression iterator */
5609 	   SCIP_HASHMAP*         exprcands           /**< map to hash variable expressions */
5610 	   )
5611 	{
5612 	   SCIP_EXPR* e;
5613 	
5614 	   for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5615 	   {
5616 	      if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5617 	      {
5618 	         SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5619 	      }
5620 	   }
5621 	
5622 	   return SCIP_OKAY;
5623 	}
5624 	
5625 	/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5626 	 *  nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5627 	 *
5628 	 *  If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5629 	 *  Otherwise, a bound disjunction constraint is added.
5630 	 *
5631 	 *  @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
5632 	 *  @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5633 	 *    g(x) to \f$\sum_i [a_i,b_i] x^{p_i}\f$ for a single variable \f$x\f$ and try to conclude montonicity or convexity/concavity
5634 	 *    on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5635 	 */
5636 	static
5637 	SCIP_RETCODE presolveSingleLockedVars(
5638 	   SCIP*                 scip,               /**< SCIP data structure */
5639 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
5640 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
5641 	   int*                  nchgvartypes,       /**< pointer to store the total number of changed variable types */
5642 	   int*                  naddconss,          /**< pointer to store the total number of added constraints */
5643 	   SCIP_Bool*            infeasible          /**< pointer to store whether problem is infeasible */
5644 	   )
5645 	{
5646 	   SCIP_CONSHDLRDATA* conshdlrdata;
5647 	   SCIP_CONSDATA* consdata;
5648 	   SCIP_EXPR** singlelocked;
5649 	   SCIP_HASHMAP* exprcands;
5650 	   SCIP_Bool hasbounddisj;
5651 	   SCIP_Bool haslhs;
5652 	   SCIP_Bool hasrhs;
5653 	   int nsinglelocked = 0;
5654 	   int i;
5655 	
5656 	   assert(conshdlr != NULL);
5657 	   assert(cons != NULL);
5658 	   assert(nchgvartypes != NULL);
5659 	   assert(naddconss != NULL);
5660 	   assert(infeasible != NULL);
5661 	
5662 	   *nchgvartypes = 0;
5663 	   *naddconss = 0;
5664 	   *infeasible = FALSE;
5665 	
5666 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
5667 	   assert(conshdlrdata != NULL);
5668 	   consdata = SCIPconsGetData(cons);
5669 	   assert(consdata != NULL);
5670 	
5671 	   /* only consider constraints with one finite side */
5672 	   if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5673 	      return SCIP_OKAY;
5674 	
5675 	   /* only consider sum expressions */
5676 	   if( !SCIPisExprSum(scip, consdata->expr) )
5677 	      return SCIP_OKAY;
5678 	
5679 	   /* remember which side is finite */
5680 	   haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5681 	   hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5682 	
5683 	   /* allocate memory */
5684 	   SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5685 	   SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5686 	
5687 	   /* check all variable expressions for single locked variables */
5688 	   for( i = 0; i < consdata->nvarexprs; ++i )
5689 	   {
5690 	      assert(consdata->varexprs[i] != NULL);
5691 	
5692 	      if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5693 	      {
5694 	         SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5695 	         singlelocked[nsinglelocked++] = consdata->varexprs[i];
5696 	      }
5697 	   }
5698 	   SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5699 	
5700 	   if( nsinglelocked > 0 )
5701 	   {
5702 	      SCIP_EXPR** children;
5703 	      SCIP_EXPRITER* it;
5704 	      int nchildren;
5705 	
5706 	      children = SCIPexprGetChildren(consdata->expr);
5707 	      nchildren = SCIPexprGetNChildren(consdata->expr);
5708 	
5709 	      /* create iterator */
5710 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
5711 	      SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
5712 	      SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR);
5713 	
5714 	      for( i = 0; i < nchildren; ++i )
5715 	      {
5716 	         SCIP_EXPR* child;
5717 	         SCIP_Real coef;
5718 	
5719 	         child = children[i];
5720 	         assert(child != NULL);
5721 	         coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5722 	
5723 	         /* ignore linear terms */
5724 	         if( SCIPisExprVar(scip, child) )
5725 	            continue;
5726 	
5727 	         /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5728 	          * expression that represents f_j and remove each variable expression from exprcands
5729 	          */
5730 	         else if( SCIPisExprProduct(scip, child) )
5731 	         {
5732 	            int j;
5733 	
5734 	            for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5735 	            {
5736 	               SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5737 	
5738 	               if( !SCIPisExprVar(scip, grandchild) )
5739 	               {
5740 	                  /* mark all variable expressions that are contained in the expression */
5741 	                  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5742 	               }
5743 	            }
5744 	         }
5745 	         /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5746 	          * for an integer k >= 1
5747 	          */
5748 	         else if( SCIPisExprPower(scip, child) )
5749 	         {
5750 	            SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5751 	            SCIP_Real exponent = SCIPgetExponentExprPow(child);
5752 	            SCIP_Bool valid;
5753 	
5754 	            /* check for even integral exponent */
5755 	            valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5756 	
5757 	            if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5758 	            {
5759 	               /* mark all variable expressions that are contained in the expression */
5760 	               SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5761 	            }
5762 	         }
5763 	         /* all other cases cannot be handled */
5764 	         else
5765 	         {
5766 	            /* mark all variable expressions that are contained in the expression */
5767 	            SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5768 	         }
5769 	      }
5770 	
5771 	      /* free expression iterator */
5772 	      SCIPfreeExpriter(&it);
5773 	   }
5774 	
5775 	   /* check whether the bound disjunction constraint handler is available */
5776 	   hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5777 	
5778 	   /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5779 	   for( i = 0; i < nsinglelocked; ++i )
5780 	   {
5781 	      /* only consider expressions that are still contained in the exprcands map */
5782 	      if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5783 	      {
5784 	         SCIP_CONS* newcons;
5785 	         SCIP_VAR* vars[2];
5786 	         SCIP_BOUNDTYPE boundtypes[2];
5787 	         SCIP_Real bounds[2];
5788 	         char name[SCIP_MAXSTRLEN];
5789 	         SCIP_VAR* var;
5790 	
5791 	         var = SCIPgetVarExprVar(singlelocked[i]);
5792 	         assert(var != NULL);
5793 	         SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5794 	            SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5795 	
5796 	         /* try to change the variable type to binary */
5797 	         if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5798 	         {
5799 	            assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5800 	            SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5801 	            ++(*nchgvartypes);
5802 	
5803 	            if( *infeasible )
5804 	            {
5805 	               SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5806 	               break;
5807 	            }
5808 	         }
5809 	         /* add bound disjunction constraint if bounds of the variable are finite */
5810 	         else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5811 	         {
5812 	            vars[0] = var;
5813 	            vars[1] = var;
5814 	            boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5815 	            boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5816 	            bounds[0] = SCIPvarGetUbGlobal(var);
5817 	            bounds[1] = SCIPvarGetLbGlobal(var);
5818 	
5819 	            SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5820 	
5821 	            /* create, add, and release bound disjunction constraint */
5822 	            (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5823 	            SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5824 	               TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5825 	            SCIP_CALL( SCIPaddCons(scip, newcons) );
5826 	            SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5827 	            ++(*naddconss);
5828 	         }
5829 	      }
5830 	   }
5831 	
5832 	   /* free memory */
5833 	   SCIPfreeBufferArray(scip, &singlelocked);
5834 	   SCIPhashmapFree(&exprcands);
5835 	
5836 	   return SCIP_OKAY;
5837 	}
5838 	
5839 	/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5840 	static
5841 	SCIP_RETCODE presolveImplint(
5842 	   SCIP*                 scip,               /**< SCIP data structure */
5843 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
5844 	   SCIP_CONS**           conss,              /**< nonlinear constraints */
5845 	   int                   nconss,             /**< total number of nonlinear constraints */
5846 	   int*                  nchgvartypes,       /**< pointer to update the total number of changed variable types */
5847 	   SCIP_Bool*            infeasible          /**< pointer to store whether problem is infeasible */
5848 	   )
5849 	{
5850 	   int c;
5851 	
5852 	   assert(scip != NULL);
5853 	   assert(conshdlr != NULL);
5854 	   assert(conss != NULL || nconss == 0);
5855 	   assert(nchgvartypes != NULL);
5856 	   assert(infeasible != NULL);
5857 	
5858 	   *infeasible = FALSE;
5859 	
5860 	   /* nothing can be done if there are no binary and integer variables available */
5861 	   if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5862 	      return SCIP_OKAY;
5863 	
5864 	   /* no continuous var can be made implicit-integer if there are no continuous variables */
5865 	   if( SCIPgetNContVars(scip) == 0 )
5866 	      return SCIP_OKAY;
5867 	
5868 	   for( c = 0; c < nconss; ++c )
5869 	   {
5870 	      SCIP_CONSDATA* consdata;
5871 	      SCIP_EXPR** children;
5872 	      int nchildren;
5873 	      SCIP_Real* coefs;
5874 	      SCIP_EXPR* cand = NULL;
5875 	      SCIP_Real candcoef = 0.0;
5876 	      int i;
5877 	
5878 	      assert(conss != NULL && conss[c] != NULL);
5879 	
5880 	      consdata = SCIPconsGetData(conss[c]);
5881 	      assert(consdata != NULL);
5882 	
5883 	      /* the constraint must be an equality constraint */
5884 	      if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5885 	         continue;
5886 	
5887 	      /* the root expression needs to be a sum expression */
5888 	      if( !SCIPisExprSum(scip, consdata->expr) )
5889 	         continue;
5890 	
5891 	      children = SCIPexprGetChildren(consdata->expr);
5892 	      nchildren = SCIPexprGetNChildren(consdata->expr);
5893 	
5894 	      /* the sum expression must have at least two children
5895 	       * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5896 	       */
5897 	      if( nchildren <= 1 )
5898 	         continue;
5899 	
5900 	      coefs = SCIPgetCoefsExprSum(consdata->expr);
5901 	
5902 	      /* find first continuous variable and get value of its coefficient */
5903 	      for( i = 0; i < nchildren; ++i )
5904 	      {
5905 	         if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5906 	            continue;
5907 	
5908 	         candcoef = coefs[i];
5909 	         assert(candcoef != 0.0);
5910 	
5911 	         /* lhs/rhs - constant divided by candcoef must be integral
5912 	          * if not, break with cand == NULL, so give up
5913 	          */
5914 	         if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5915 	            cand = children[i];
5916 	
5917 	         break;
5918 	      }
5919 	
5920 	      /* no suitable continuous variable found */
5921 	      if( cand == NULL )
5922 	         continue;
5923 	
5924 	      /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5925 	      for( i = 0; i < nchildren; ++i )
5926 	      {
5927 	         if( children[i] == cand )
5928 	            continue;
5929 	
5930 	         /* child i must be integral */
5931 	         if( !SCIPexprIsIntegral(children[i]) )
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",
5949 	         SCIPvarGetName(SCIPgetVarExprVar(cand)), SCIPconsGetName(conss[c]));
5950 	
5951 	      /* change variable type */
5952 	      SCIP_CALL( SCIPchgVarType(scip, SCIPgetVarExprVar(cand), SCIP_VARTYPE_IMPLINT, infeasible) );
5953 	
5954 	      if( *infeasible )
5955 	         return SCIP_OKAY;
5956 	
5957 	      /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5958 	      SCIPexprSetIntegrality(cand, TRUE);
5959 	   }
5960 	
5961 	   return SCIP_OKAY;
5962 	}
5963 	
5964 	/** creates auxiliary variable for a given expression
5965 	 *
5966 	 * @note for a variable expression it does nothing
5967 	 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5968 	 */
5969 	static
5970 	SCIP_RETCODE createAuxVar(
5971 	   SCIP*                 scip,               /**< SCIP data structure */
5972 	   SCIP_EXPR*            expr                /**< expression */
5973 	   )
5974 	{
5975 	   SCIP_EXPR_OWNERDATA* ownerdata;
5976 	   SCIP_CONSHDLRDATA* conshdlrdata;
5977 	   SCIP_VARTYPE vartype;
5978 	   SCIP_INTERVAL activity;
5979 	   char name[SCIP_MAXSTRLEN];
5980 	
5981 	   assert(scip != NULL);
5982 	   assert(expr != NULL);
5983 	
5984 	   ownerdata = SCIPexprGetOwnerData(expr);
5985 	   assert(ownerdata != NULL);
5986 	   assert(ownerdata->nauxvaruses > 0);
5987 	
5988 	   /* if we already have auxvar, then do nothing */
5989 	   if( ownerdata->auxvar != NULL )
5990 	      return SCIP_OKAY;
5991 	
5992 	   /* if expression is a variable-expression, then do nothing */
5993 	   if( SCIPisExprVar(scip, expr) )
5994 	      return SCIP_OKAY;
5995 	
5996 	   if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
5997 	   {
5998 	      SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
5999 	      return SCIP_INVALIDCALL;
6000 	   }
6001 	
6002 	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6003 	   assert(conshdlrdata != NULL);
6004 	   assert(conshdlrdata->auxvarid >= 0);
6005 	
6006 	   /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6007 	    * but it usually indicates a missing simplify
6008 	    * if we find situations where we need to have an auxvar for a constant, then remove this assert
6009 	    */
6010 	   assert(!SCIPisExprValue(scip, expr));
6011 	
6012 	   /* create and capture auxiliary variable */
6013 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6014 	   ++conshdlrdata->auxvarid;
6015 	
6016 	   /* type of auxiliary variable depends on integrality information of the expression */
6017 	   vartype = SCIPexprIsIntegral(expr) ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS;
6018 	
6019 	   /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6020 	   if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6021 	   {
6022 	      activity = SCIPexprGetActivity(expr);
6023 	      /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6024 	       * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6025 	       * and abort in debug mode only
6026 	       */
6027 	      if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity) )
6028 	      {
6029 	         SCIPABORT();
6030 	         SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
6031 	      }
6032 	   }
6033 	   else
6034 	      SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
6035 	
6036 	   /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6037 	    * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6038 	    */
6039 	   if( SCIPgetDepth(scip) == 0 )
6040 	   {
6041 	      SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
6042 	   }
6043 	   else
6044 	   {
6045 	      SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
6046 	   }
6047 	
6048 	   /* mark the auxiliary variable to be added for the relaxation only
6049 	    * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6050 	    * or to copy the variable to a subscip
6051 	    */
6052 	   SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6053 	
6054 	   SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6055 	
6056 	   SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6057 	
6058 	   /* add variable locks in both directions
6059 	    * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6060 	    *   but then we need to also update the auxvars locks when the expr locks change
6061 	    */
6062 	   SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6063 	
6064 	#ifdef WITH_DEBUG_SOLUTION
6065 	   if( SCIPdebugIsMainscip(scip) )
6066 	   {
6067 	      /* store debug solution value of auxiliary variable
6068 	       * assumes that expression has been evaluated in debug solution before
6069 	       */
6070 	      SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6071 	   }
6072 	#endif
6073 	
6074 	   if( SCIPgetDepth(scip) > 0 )
6075 	   {
6076 	      /* initialize local bounds to (locally valid) activity */
6077 	      SCIP_Bool cutoff;
6078 	      SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6079 	      assert(!cutoff);  /* should not happen as activity wasn't empty and variable is new */
6080 	   }
6081 	
6082 	   return SCIP_OKAY;
6083 	}
6084 	
6085 	/** initializes separation for constraint
6086 	 *
6087 	 * - ensures that activities are up to date in all expressions
6088 	 * - creates auxiliary variables where required
6089 	 * - calls propExprDomains() to possibly tighten auxvar bounds
6090 	 * - calls separation initialization callback of nlhdlrs
6091 	 */
6092 	static
6093 	SCIP_RETCODE initSepa(
6094 	   SCIP*                 scip,               /**< SCIP data structure */
6095 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6096 	   SCIP_CONS**           conss,              /**< constraints */
6097 	   int                   nconss,             /**< number of constraints */
6098 	   SCIP_Bool*            infeasible          /**< pointer to store whether the problem is infeasible or not */
6099 	   )
6100 	{
6101 	   SCIP_CONSDATA* consdata;
6102 	   SCIP_CONSHDLRDATA* conshdlrdata;
6103 	   SCIP_EXPRITER* it;
6104 	   SCIP_EXPR* expr;
6105 	   SCIP_RESULT result;
6106 	   SCIP_VAR* auxvar;
6107 	   int nreductions = 0;
6108 	   int c, e;
6109 	
6110 	   assert(scip != NULL);
6111 	   assert(conshdlr != NULL);
6112 	   assert(conss != NULL || nconss == 0);
6113 	   assert(nconss >= 0);
6114 	   assert(infeasible != NULL);
6115 	
6116 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6117 	   assert(conshdlrdata != NULL);
6118 	
6119 	   /* start with new propbounds (just to be sure, should not be needed) */
6120 	   ++conshdlrdata->curpropboundstag;
6121 	
6122 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6123 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6124 	
6125 	   /* first ensure activities are up to date and create auxvars */
6126 	   *infeasible = FALSE;
6127 	   for( c = 0; c < nconss; ++c )
6128 	   {
6129 	      assert(conss != NULL);
6130 	      assert(conss[c] != NULL);
6131 	
6132 	      consdata = SCIPconsGetData(conss[c]);
6133 	      assert(consdata != NULL);
6134 	      assert(consdata->expr != NULL);
6135 	
6136 	#ifdef WITH_DEBUG_SOLUTION
6137 	      if( SCIPdebugIsMainscip(scip) )
6138 	      {
6139 	         SCIP_SOL* debugsol;
6140 	
6141 	         SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6142 	
6143 	         if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6144 	         {
6145 	            /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6146 	             * in createAuxVar()
6147 	             */
6148 	            SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6149 	         }
6150 	      }
6151 	#endif
6152 	
6153 	      /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6154 	      SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6155 	
6156 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6157 	      {
6158 	         if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6159 	         {
6160 	            SCIP_CALL( createAuxVar(scip, expr) );
6161 	         }
6162 	      }
6163 	
6164 	      auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6165 	      if( auxvar != NULL )
6166 	      {
6167 	         SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6168 	               SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6169 	         /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6170 	         SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6171 	         if( *infeasible )
6172 	         {
6173 	            SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6174 	            break;
6175 	         }
6176 	
6177 	         SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6178 	         if( *infeasible )
6179 	         {
6180 	            SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6181 	            break;
6182 	         }
6183 	      }
6184 	   }
6185 	
6186 	   /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6187 	    * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6188 	    * (e.g., log(x*y), which becomes log(w), w=x*y
6189 	    *  log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6190 	    */
6191 	   SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6192 	   if( result == SCIP_CUTOFF )
6193 	      *infeasible = TRUE;
6194 	
6195 	   /* now call initsepa of nlhdlrs
6196 	    * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6197 	    *   but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6198 	    */
6199 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6200 	   for( c = 0; c < nconss && !*infeasible; ++c )
6201 	   {
6202 	      assert(conss != NULL);
6203 	      assert(conss[c] != NULL);
6204 	
6205 	      consdata = SCIPconsGetData(conss[c]);
6206 	      assert(consdata != NULL);
6207 	      assert(consdata->expr != NULL);
6208 	
6209 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6210 	      {
6211 	         SCIP_EXPR_OWNERDATA* ownerdata;
6212 	
6213 	         ownerdata = SCIPexprGetOwnerData(expr);
6214 	         assert(ownerdata != NULL);
6215 	
6216 	         if( ownerdata->nauxvaruses == 0 )
6217 	            continue;
6218 	
6219 	         for( e = 0; e < ownerdata->nenfos; ++e )
6220 	         {
6221 	            SCIP_NLHDLR* nlhdlr;
6222 	            SCIP_Bool underestimate;
6223 	            SCIP_Bool overestimate;
6224 	            assert(ownerdata->enfos[e] != NULL);
6225 	
6226 	            /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6227 	             * which participated in a previous initSepa() call
6228 	             */
6229 	            if( ownerdata->enfos[e]->issepainit )
6230 	               continue;
6231 	
6232 	            /* only call initsepa if it will actually separate */
6233 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6234 	               continue;
6235 	
6236 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
6237 	            assert(nlhdlr != NULL);
6238 	
6239 	            /* only init sepa if there is an initsepa callback */
6240 	            if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6241 	               continue;
6242 	
6243 	            /* check whether expression needs to be under- or overestimated */
6244 	            overestimate = ownerdata->nlocksneg > 0;
6245 	            underestimate = ownerdata->nlockspos > 0;
6246 	            assert(underestimate || overestimate);
6247 	
6248 	            SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6249 	
6250 	            /* call the separation initialization callback of the nonlinear handler */
6251 	            SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6252 	               ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6253 	            ownerdata->enfos[e]->issepainit = TRUE;
6254 	
6255 	            if( *infeasible )
6256 	            {
6257 	               /* stop everything if we detected infeasibility */
6258 	               SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6259 	               break;
6260 	            }
6261 	         }
6262 	      }
6263 	   }
6264 	
6265 	   SCIPfreeExpriter(&it);
6266 	
6267 	   return SCIP_OKAY;
6268 	}
6269 	
6270 	/** returns whether we are ok to branch on auxiliary variables
6271 	 *
6272 	 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6273 	 */
6274 	static
6275 	SCIP_Bool branchAuxNonlinear(
6276 	   SCIP*                 scip,               /**< SCIP data structure */
6277 	   SCIP_CONSHDLR*        conshdlr            /**< constraint handler */
6278 	   )
6279 	{
6280 	   SCIP_CONSHDLRDATA* conshdlrdata;
6281 	
6282 	   assert(conshdlr != NULL);
6283 	
6284 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6285 	   assert(conshdlrdata != NULL);
6286 	
6287 	   return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6288 	}
6289 	
6290 	/** gets weight of variable when splitting violation score onto several variables in an expression */
6291 	static
6292 	SCIP_Real getViolSplitWeight(
6293 	   SCIP*                 scip,               /**< SCIP data structure */
6294 	   SCIP_CONSHDLR*        conshdlr,           /**< expr constraint handler */
6295 	   SCIP_VAR*             var,                /**< variable */
6296 	   SCIP_SOL*             sol                 /**< current solution */
6297 	   )
6298 	{
6299 	   SCIP_CONSHDLRDATA* conshdlrdata;
6300 	
6301 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6302 	   assert(conshdlrdata != NULL);
6303 	
6304 	   switch( conshdlrdata->branchviolsplit )
6305 	   {
6306 	      case 'u' :  /* uniform: everyone gets the same score */
6307 	         return 1.0;
6308 	
6309 	      case 'm' :  /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6310 	      {
6311 	         SCIP_Real weight;
6312 	         weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6313 	         return MAX(0.05, weight);
6314 	      }
6315 	
6316 	      case 'd' :  /* domain width */
6317 	         return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6318 	
6319 	      case 'l' :  /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6320 	      {
6321 	         SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6322 	         assert(width > 0.0);
6323 	         if( width > 10.0 )
6324 	            return 10.0*log10(width);
6325 	         if( width < 0.1 )
6326 	            return 0.1/(-log10(width));
6327 	         return width;
6328 	      }
6329 	
6330 	      default :
6331 	         SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6332 	         SCIPABORT();
6333 	         return SCIP_INVALID;
6334 	   }
6335 	}
6336 	
6337 	/** adds violation-branching score to a set of expressions, thereby distributing the score
6338 	 *
6339 	 * Each expression must either be a variable expression or have an aux-variable.
6340 	 *
6341 	 * If unbounded variables are present, each unbounded var gets an even score.
6342 	 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6343 	 */
6344 	static
6345 	void addExprsViolScore(
6346 	   SCIP*                 scip,               /**< SCIP data structure */
6347 	   SCIP_EXPR**           exprs,              /**< expressions where to add branching score */
6348 	   int                   nexprs,             /**< number of expressions */
6349 	   SCIP_Real             violscore,          /**< violation-branching score to add to expression */
6350 	   SCIP_SOL*             sol,                /**< current solution */
6351 	   SCIP_Bool*            success             /**< buffer to store whether at least one violscore was added */
6352 	   )
6353 	{
6354 	   SCIP_CONSHDLR* conshdlr;
6355 	   SCIP_VAR* var;
6356 	   SCIP_Real weight;
6357 	   SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6358 	   int nunbounded = 0;  /* number of candidates with unbounded domain */
6359 	   int i;
6360 	
6361 	   assert(exprs != NULL);
6362 	   assert(nexprs > 0);
6363 	   assert(success != NULL);
6364 	
6365 	   if( nexprs == 1 )
6366 	   {
6367 	      SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6368 	      SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6369 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(exprs[0])), SCIPvarGetLbLocal(SCIPgetExprAuxVarNonlinear(exprs[0])), SCIPvarGetUbLocal(SCIPgetExprAuxVarNonlinear(exprs[0])));
6370 	      *success = TRUE;
6371 	      return;
6372 	   }
6373 	
6374 	   conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6375 	
6376 	   for( i = 0; i < nexprs; ++i )
6377 	   {
6378 	      var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6379 	      assert(var != NULL);
6380 	
6381 	      if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6382 	         ++nunbounded;
6383 	      else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6384 	         weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6385 	   }
6386 	
6387 	   *success = FALSE;
6388 	   for( i = 0; i < nexprs; ++i )
6389 	   {
6390 	      var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6391 	      assert(var != NULL);
6392 	
6393 	      if( nunbounded > 0 )
6394 	      {
6395 	         if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6396 	         {
6397 	            SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6398 	            SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6399 	               100.0/nunbounded, violscore,
6400 	               SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6401 	            *success = TRUE;
6402 	         }
6403 	      }
6404 	      else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6405 	      {
6406 	         assert(weightsum > 0.0);
6407 	
6408 	         weight = getViolSplitWeight(scip, conshdlr, var, sol);
6409 	         SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6410 	         SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6411 	            100*weight / weightsum, violscore,
6412 	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6413 	         *success = TRUE;
6414 	      }
6415 	      else
6416 	      {
6417 	         SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6418 	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6419 	      }
6420 	   }
6421 	}
6422 	
6423 	/** adds violation-branching score to children of expression for given auxiliary variables
6424 	 *
6425 	 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6426 	 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6427 	 *
6428 	 * @note This method may modify the given auxvars array by means of sorting.
6429 	 */
6430 	static
6431 	SCIP_RETCODE addExprViolScoresAuxVars(
6432 	   SCIP*                 scip,               /**< SCIP data structure */
6433 	   SCIP_EXPR*            expr,               /**< expression where to start searching */
6434 	   SCIP_Real             violscore,          /**< violation score to add to expression */
6435 	   SCIP_VAR**            auxvars,            /**< auxiliary variables for which to find expression */
6436 	   int                   nauxvars,           /**< number of auxiliary variables */
6437 	   SCIP_SOL*             sol,                /**< current solution (NULL for the LP solution) */
6438 	   SCIP_Bool*            success             /**< buffer to store whether at least one violscore was added */
6439 	   )
6440 	{
6441 	   SCIP_EXPRITER* it;
6442 	   SCIP_VAR* auxvar;
6443 	   SCIP_EXPR** exprs;
6444 	   int nexprs;
6445 	   int pos;
6446 	
6447 	   assert(scip != NULL);
6448 	   assert(expr != NULL);
6449 	   assert(auxvars != NULL);
6450 	   assert(success != NULL);
6451 	
6452 	   /* sort variables to make lookup below faster */
6453 	   SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6454 	
6455 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6456 	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_BFS, FALSE) );
6457 	
6458 	   SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6459 	   nexprs = 0;
6460 	
6461 	   for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6462 	   {
6463 	      auxvar = SCIPgetExprAuxVarNonlinear(expr);
6464 	      if( auxvar == NULL )
6465 	         continue;
6466 	
6467 	      /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6468 	      if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6469 	      {
6470 	         assert(auxvars[pos] == auxvar);
6471 	
6472 	         SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6473 	         exprs[nexprs++] = expr;
6474 	
6475 	         if( nexprs == nauxvars )
6476 	            break;
6477 	      }
6478 	   }
6479 	
6480 	   SCIPfreeExpriter(&it);
6481 	
6482 	   if( nexprs > 0 )
6483 	   {
6484 	      SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6485 	   }
6486 	   else
6487 	      *success = FALSE;
6488 	
6489 	   SCIPfreeBufferArray(scip, &exprs);
6490 	
6491 	   return SCIP_OKAY;
6492 	}
6493 	
6494 	/** registers all unfixed variables in violated constraints as branching candidates */
6495 	static
6496 	SCIP_RETCODE registerBranchingCandidatesAllUnfixed(
6497 	   SCIP*                 scip,               /**< SCIP data structure */
6498 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6499 	   SCIP_CONS**           conss,              /**< constraints */
6500 	   int                   nconss,             /**< number of constraints */
6501 	   int*                  nnotify             /**< counter for number of notifications performed */
6502 	   )
6503 	{
6504 	   SCIP_CONSDATA* consdata;
6505 	   SCIP_VAR* var;
6506 	   int c;
6507 	   int i;
6508 	
6509 	   assert(conshdlr != NULL);
6510 	   assert(conss != NULL || nconss == 0);
6511 	   assert(nnotify != NULL);
6512 	
6513 	   *nnotify = 0;
6514 	
6515 	   for( c = 0; c < nconss; ++c )
6516 	   {
6517 	      assert(conss != NULL && conss[c] != NULL);
6518 	
6519 	      consdata = SCIPconsGetData(conss[c]);
6520 	      assert(consdata != NULL);
6521 	
6522 	      /* consider only violated constraints */
6523 	      if( !isConsViolated(scip, conss[c]) )
6524 	         continue;
6525 	
6526 	      /* register all variables that have not been fixed yet */
6527 	      assert(consdata->varexprs != NULL);
6528 	      for( i = 0; i < consdata->nvarexprs; ++i )
6529 	      {
6530 	         var = SCIPgetVarExprVar(consdata->varexprs[i]);
6531 	         assert(var != NULL);
6532 	
6533 	         if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6534 	         {
6535 	            SCIP_CALL( SCIPaddExternBranchCand(scip, var, getConsAbsViolation(conss[c]), SCIP_INVALID) );
6536 	            ++(*nnotify);
6537 	         }
6538 	      }
6539 	   }
6540 	
6541 	   return SCIP_OKAY;
6542 	}
6543 	
6544 	/** registers all variables in violated constraints with branching scores as external branching candidates */
6545 	static
6546 	SCIP_RETCODE registerBranchingCandidates(
6547 	   SCIP*                 scip,               /**< SCIP data structure */
6548 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6549 	   SCIP_CONS**           conss,              /**< constraints */
6550 	   int                   nconss,             /**< number of constraints */
6551 	   SCIP_Bool*            success             /**< buffer to store whether at least one branching candidate was added */
6552 	   )
6553 	{
6554 	   SCIP_CONSDATA* consdata;
6555 	   SCIP_EXPRITER* it = NULL;
6556 	   int c;
6557 	
6558 	   assert(conshdlr != NULL);
6559 	   assert(success != NULL);
6560 	
6561 	   *success = FALSE;
6562 	
6563 	   if( branchAuxNonlinear(scip, conshdlr) )
6564 	   {
6565 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6566 	      SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6567 	   }
6568 	
6569 	   /* register external branching candidates */
6570 	   for( c = 0; c < nconss; ++c )
6571 	   {
6572 	      assert(conss != NULL && conss[c] != NULL);
6573 	
6574 	      consdata = SCIPconsGetData(conss[c]);
6575 	      assert(consdata != NULL);
6576 	      assert(consdata->varexprs != NULL);
6577 	
6578 	      /* consider only violated constraints */
6579 	      if( !isConsViolated(scip, conss[c]) )
6580 	         continue;
6581 	
6582 	      if( !branchAuxNonlinear(scip, conshdlr) )
6583 	      {
6584 	         int i;
6585 	
6586 	         /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6587 	          * only, so we can loop over variable expressions
6588 	          */
6589 	         for( i = 0; i < consdata->nvarexprs; ++i )
6590 	         {
6591 	            SCIP_Real violscore;
6592 	            SCIP_Real lb;
6593 	            SCIP_Real ub;
6594 	            SCIP_VAR* var;
6595 	
6596 	            violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6597 	
6598 	            /* skip variable expressions that do not have a violation score */
6599 	            if( violscore == 0.0 )
6600 	               continue;
6601 	
6602 	            var = SCIPgetVarExprVar(consdata->varexprs[i]);
6603 	            assert(var != NULL);
6604 	
6605 	            lb = SCIPvarGetLbLocal(var);
6606 	            ub = SCIPvarGetUbLocal(var);
6607 	
6608 	            /* consider variable for branching if it has not been fixed yet */
6609 	            if( !SCIPisEQ(scip, lb, ub) )
6610 	            {
6611 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6612 	               SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6613 	               *success = TRUE;
6614 	            }
6615 	            else
6616 	            {
6617 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6618 	            }
6619 	
6620 	            /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6621 	             * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6622 	             */
6623 	            SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6624 	         }
6625 	      }
6626 	      else
6627 	      {
6628 	         SCIP_EXPR* expr;
6629 	         SCIP_VAR* var;
6630 	         SCIP_Real lb;
6631 	         SCIP_Real ub;
6632 	         SCIP_Real violscore;
6633 	
6634 	         for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6635 	         {
6636 	            violscore = SCIPgetExprViolScoreNonlinear(expr);
6637 	            if( violscore == 0.0 )
6638 	               continue;
6639 	
6640 	            /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6641 	             * variable, so this expression should either be an original variable or have an auxiliary variable
6642 	             */
6643 	            var = SCIPgetExprAuxVarNonlinear(expr);
6644 	            assert(var != NULL);
6645 	
6646 	            lb = SCIPvarGetLbLocal(var);
6647 	            ub = SCIPvarGetUbLocal(var);
6648 	
6649 	            /* consider variable for branching if it has not been fixed yet */
6650 	            if( !SCIPisEQ(scip, lb, ub) )
6651 	            {
6652 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6653 	
6654 	               SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6655 	               *success = TRUE;
6656 	            }
6657 	            else
6658 	            {
6659 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6660 	            }
6661 	         }
6662 	      }
6663 	   }
6664 	
6665 	   if( it != NULL )
6666 	      SCIPfreeExpriter(&it);
6667 	
6668 	   return SCIP_OKAY;
6669 	}
6670 	
6671 	/** collect branching candidates from violated constraints
6672 	 *
6673 	 * Fills array with expressions that serve as branching candidates.
6674 	 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6675 	 * branching candidate.
6676 	 *
6677 	 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6678 	 * through variable-expressions only.
6679 	 */
6680 	static
6681 	SCIP_RETCODE collectBranchingCandidates(
6682 	   SCIP*                 scip,               /**< SCIP data structure */
6683 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6684 	   SCIP_CONS**           conss,              /**< constraints to process */
6685 	   int                   nconss,             /**< number of constraints */
6686 	   SCIP_Real             maxrelconsviol,     /**< maximal scaled constraint violation */
6687 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
6688 	   SCIP_Longint          soltag,             /**< tag of solution */
6689 	   BRANCHCAND*           cands,              /**< array where to store candidates, must be at least SCIPgetNVars() long */
6690 	   int*                  ncands              /**< number of candidates found */
6691 	   )
6692 	{
6693 	   SCIP_CONSHDLRDATA* conshdlrdata;
6694 	   SCIP_CONSDATA* consdata;
6695 	   SCIP_EXPRITER* it = NULL;
6696 	   int c;
6697 	   int attempt;
6698 	   SCIP_VAR* var;
6699 	
6700 	   assert(scip != NULL);
6701 	   assert(conshdlr != NULL);
6702 	   assert(cands != NULL);
6703 	   assert(ncands != NULL);
6704 	
6705 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6706 	   assert(conshdlrdata != NULL);
6707 	
6708 	   if( branchAuxNonlinear(scip, conshdlr) )
6709 	   {
6710 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6711 	      SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6712 	   }
6713 	
6714 	   *ncands = 0;
6715 	   for( attempt = 0; attempt < 2; ++attempt )
6716 	   {
6717 	      /* collect branching candidates from violated constraints
6718 	       * in the first attempt, consider only constraints with large violation
6719 	       * in the second attempt, consider all remaining violated constraints
6720 	       */
6721 	      for( c = 0; c < nconss; ++c )
6722 	      {
6723 	         SCIP_Real consviol;
6724 	
6725 	         assert(conss != NULL && conss[c] != NULL);
6726 	
6727 	         /* consider only violated constraints */
6728 	         if( !isConsViolated(scip, conss[c]) )
6729 	            continue;
6730 	
6731 	         consdata = SCIPconsGetData(conss[c]);
6732 	         assert(consdata != NULL);
6733 	         assert(consdata->varexprs != NULL);
6734 	
6735 	         SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6736 	
6737 	         if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6738 	            continue;
6739 	         else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6740 	            continue;
6741 	
6742 	         if( !branchAuxNonlinear(scip, conshdlr) )
6743 	         {
6744 	            int i;
6745 	
6746 	            /* if not branching on auxvars, then violation-branching scores will be available for original variables
6747 	             * only, so we can loop over variable expressions
6748 	             * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6749 	             * variable, therefore we invalidate the score of a variable after processing it.
6750 	             */
6751 	            for( i = 0; i < consdata->nvarexprs; ++i )
6752 	            {
6753 	               SCIP_Real lb;
6754 	               SCIP_Real ub;
6755 	
6756 	               /* skip variable expressions that do not have a valid violation score */
6757 	               if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6758 	                  continue;
6759 	
6760 	               var = SCIPgetVarExprVar(consdata->varexprs[i]);
6761 	               assert(var != NULL);
6762 	
6763 	               lb = SCIPvarGetLbLocal(var);
6764 	               ub = SCIPvarGetUbLocal(var);
6765 	
6766 	               /* skip already fixed variable */
6767 	               if( SCIPisEQ(scip, lb, ub) )
6768 	               {
6769 	                  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6770 	                  continue;
6771 	               }
6772 	
6773 	               assert(*ncands + 1 < SCIPgetNVars(scip));
6774 	               cands[*ncands].expr = consdata->varexprs[i];
6775 	               cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6776 	               ++(*ncands);
6777 	
6778 	               /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6779 	                * several times as external branching candidate */
6780 	               SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6781 	            }
6782 	         }
6783 	         else
6784 	         {
6785 	            SCIP_EXPR* expr;
6786 	            SCIP_Real lb;
6787 	            SCIP_Real ub;
6788 	
6789 	            for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6790 	            {
6791 	               if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6792 	                  continue;
6793 	
6794 	               /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6795 	                * variables, so this expression should either be an original variable or have an auxiliary variable
6796 	                */
6797 	               var = SCIPgetExprAuxVarNonlinear(expr);
6798 	               assert(var != NULL);
6799 	
6800 	               lb = SCIPvarGetLbLocal(var);
6801 	               ub = SCIPvarGetUbLocal(var);
6802 	
6803 	               /* skip already fixed variable */
6804 	               if( SCIPisEQ(scip, lb, ub) )
6805 	               {
6806 	                  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6807 	                  continue;
6808 	               }
6809 	
6810 	               assert(*ncands + 1 < SCIPgetNVars(scip));
6811 	               cands[*ncands].expr = expr;
6812 	               cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6813 	               ++(*ncands);
6814 	            }
6815 	         }
6816 	      }
6817 	
6818 	      /* if we have branching candidates, then we don't need another attempt */
6819 	      if( *ncands > 0 )
6820 	         break;
6821 	   }
6822 	
6823 	   if( it != NULL )
6824 	      SCIPfreeExpriter(&it);
6825 	
6826 	   return SCIP_OKAY;
6827 	}
6828 	
6829 	/** computes a branching score for a variable that reflects how important branching on this variable would be for
6830 	 * improving the dual bound from the LP relaxation
6831 	 *
6832 	 * Assume the Lagrangian for the current LP is something of the form
6833 	 *   L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6834 	 * where x are the original variables, z the auxiliary variables,
6835 	 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6836 	 *
6837 	 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6838 	 * If we could have used not only an estimator, but the actual function f(x), then this would
6839 	 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6840 	 * Using a lot of handwaving, we claim that
6841 	 *   lambda_i * (f(x) - a_i'x + b_i)
6842 	 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6843 	 * If an estimator depended on local bounds, then it could be improved by branching.
6844 	 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6845 	 *
6846 	 * 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.
6847 	 * To scale, we divide by the LP objective value (if >1).
6848 	 *
6849 	 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6850 	 *     these are affected by the bounds on original variables indirectly (through forward-propagation)
6851 	 *
6852 	 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6853 	 *     in effect, we should go from the row to the expression for which it was generated and consider only variables that
6854 	 *     would also be branching candidates
6855 	 */
6856 	static
6857 	SCIP_Real getDualBranchscore(
6858 	   SCIP*                 scip,               /**< SCIP data structure */
6859 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6860 	   SCIP_VAR*             var                 /**< variable */
6861 	   )
6862 	{
6863 	   SCIP_COL* col;
6864 	   SCIP_ROW** rows;
6865 	   int nrows;
6866 	   int r;
6867 	   SCIP_Real dualscore;
6868 	
6869 	   assert(scip != NULL);
6870 	   assert(conshdlr != NULL);
6871 	   assert(var != NULL);
6872 	
6873 	   /* if LP not solved, then the dual branching score is not available */
6874 	   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
6875 	      return 0.0;
6876 	
6877 	   /* if var is not in the LP, then the dual branching score is not available */
6878 	   if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
6879 	      return 0.0;
6880 	
6881 	   col = SCIPvarGetCol(var);
6882 	   assert(col != NULL);
6883 	
6884 	   if( !SCIPcolIsInLP(col) )
6885 	      return 0.0;
6886 	
6887 	   nrows = SCIPcolGetNLPNonz(col);  /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6888 	   rows = SCIPcolGetRows(col);
6889 	
6890 	   /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6891 	
6892 	   /* aggregate duals from all rows from consexpr with non-zero dual
6893 	    * TODO: this is a quick-and-dirty implementation, and not used by default
6894 	    *   in the long run, this should be either removed or replaced by a proper implementation
6895 	    */
6896 	   dualscore = 0.0;
6897 	   for( r = 0; r < nrows; ++r )
6898 	   {
6899 	      SCIP_Real estimategap;
6900 	      const char* estimategapstr;
6901 	
6902 	      /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6903 	       * these would typically be local, unless they are created at the root node
6904 	       * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6905 	      if( !SCIProwIsLocal(rows[r]) )
6906 	         continue;
6907 	       */
6908 	      if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6909 	         continue;
6910 	      if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6911 	         continue;
6912 	
6913 	      estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6914 	      if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6915 	         continue;
6916 	      estimategap = atof(estimategapstr + 13);
6917 	      assert(estimategap >= 0.0);
6918 	      if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6919 	         estimategap = SCIPgetHugeValue(scip);
6920 	
6921 	      /* SCIPinfoMessage(scip, enfologfile, "  row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6922 	      SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6923 	
6924 	      dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6925 	   }
6926 	
6927 	   /* divide by optimal value of LP for scaling */
6928 	   dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6929 	
6930 	   return dualscore;
6931 	}
6932 	
6933 	/** computes branching scores (including weighted score) for a set of candidates
6934 	 *
6935 	 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6936 	 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6937 	 *
6938 	 * For each score, compute the maximum over all candidates.
6939 	 *
6940 	 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6941 	 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6942 	 * score of all candidates.
6943 	 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6944 	 *
6945 	 * For example:
6946 	 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6947 	 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6948 	 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6949 	 * - 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.
6950 	 *   The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6951 	 */
6952 	static
6953 	void scoreBranchingCandidates(
6954 	   SCIP*                 scip,               /**< SCIP data structure */
6955 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6956 	   BRANCHCAND*           cands,              /**< branching candidates */
6957 	   int                   ncands,             /**< number of candidates */
6958 	   SCIP_SOL*             sol                 /**< solution to enforce (NULL for the LP solution) */
6959 	   )
6960 	{
6961 	   SCIP_CONSHDLRDATA* conshdlrdata;
6962 	   BRANCHCAND maxscore;
6963 	   int c;
6964 	
6965 	   assert(scip != NULL);
6966 	   assert(conshdlr != NULL);
6967 	   assert(cands != NULL);
6968 	   assert(ncands > 0);
6969 	
6970 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6971 	   assert(conshdlrdata != NULL);
6972 	
6973 	   /* initialize counts to 0 */
6974 	   memset(&maxscore, 0, sizeof(BRANCHCAND));
6975 	
6976 	   for( c = 0; c < ncands; ++c )
6977 	   {
6978 	      if( conshdlrdata->branchviolweight > 0.0 )
6979 	      {
6980 	         /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6981 	         maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6982 	      }
6983 	
6984 	      if( conshdlrdata->branchdomainweight > 0.0 )
6985 	      {
6986 	         SCIP_Real domainwidth;
6987 	         SCIP_VAR* var;
6988 	
6989 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6990 	         assert(var != NULL);
6991 	
6992 	         /* get domain width, taking infinity at 1e20 on purpose */
6993 	         domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6994 	
6995 	         /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6996 	          * and log(2 * infinity *  MAX(epsilon, domainwidth)) for domain width < 1
6997 	          * the idea is to penalize very large and very small domains
6998 	          */
6999 	         if( domainwidth >= 1.0 )
7000 	            cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7001 	         else
7002 	            cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
7003 	
7004 	         maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7005 	      }
7006 	      else
7007 	         cands[c].domain = 0.0;
7008 	
7009 	      if( conshdlrdata->branchdualweight > 0.0 )
7010 	      {
7011 	         SCIP_VAR* var;
7012 	
7013 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7014 	         assert(var != NULL);
7015 	
7016 	         cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7017 	         maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7018 	      }
7019 	
7020 	      if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7021 	      {
7022 	         SCIP_VAR* var;
7023 	
7024 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7025 	         assert(var != NULL);
7026 	
7027 	         if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
7028 	            cands[c].pscost = SCIP_INVALID;
7029 	         else
7030 	         {
7031 	            SCIP_Real brpoint;
7032 	            SCIP_Real pscostdown;
7033 	            SCIP_Real pscostup;
7034 	            char strategy;
7035 	
7036 	            /* decide how to compute pseudo-cost scores
7037 	             * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7038 	             * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7039 	             */
7040 	            if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
7041 	               strategy = conshdlrdata->branchpscostupdatestrategy;
7042 	            else
7043 	               strategy = 'l';
7044 	
7045 	            brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7046 	
7047 	            /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7048 	             * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7049 	             * For here, I use a simple #counts >= branchpscostreliable.
7050 	             * TODO use SCIPgetVarPseudocostCount() instead?
7051 	             */
7052 	            if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7053 	            {
7054 	               switch( strategy )
7055 	               {
7056 	                  case 's' :
7057 	                     pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7058 	                     break;
7059 	                  case 'd' :
7060 	                     pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7061 	                     break;
7062 	                  case 'l' :
7063 	                     if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7064 	                        pscostdown = SCIP_INVALID;
7065 	                     else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7066 	                        pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7067 	                     else
7068 	                        pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, NULL, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7069 	                     break;
7070 	                  default :
7071 	                     SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7072 	                     pscostdown = SCIP_INVALID;
7073 	               }
7074 	            }
7075 	            else
7076 	               pscostdown = SCIP_INVALID;
7077 	
7078 	            if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7079 	            {
7080 	               switch( strategy )
7081 	               {
7082 	                  case 's' :
7083 	                     pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7084 	                     break;
7085 	                  case 'd' :
7086 	                     pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7087 	                     break;
7088 	                  case 'l' :
7089 	                     if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7090 	                        pscostup = SCIP_INVALID;
7091 	                     else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7092 	                        pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7093 	                     else
7094 	                        pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, NULL, var) );
7095 	                     break;
7096 	                  default :
7097 	                     SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7098 	                     pscostup = SCIP_INVALID;
7099 	               }
7100 	            }
7101 	            else
7102 	               pscostup = SCIP_INVALID;
7103 	
7104 	            /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7105 	             * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7106 	             */
7107 	            if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7108 	               cands[c].pscost = SCIP_INVALID;
7109 	            else if( pscostdown == SCIP_INVALID )
7110 	               cands[c].pscost = pscostup;
7111 	            else if( pscostup == SCIP_INVALID )
7112 	               cands[c].pscost = pscostdown;
7113 	            else
7114 	               cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup);  /* pass NULL for var to avoid multiplication with branch-factor */
7115 	         }
7116 	
7117 	         if( cands[c].pscost != SCIP_INVALID )
7118 	            maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7119 	      }
7120 	
7121 	      if( conshdlrdata->branchvartypeweight > 0.0 )
7122 	      {
7123 	         SCIP_VAR* var;
7124 	
7125 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7126 	         assert(var != NULL);
7127 	
7128 	         switch( SCIPvarGetType(var) )
7129 	         {
7130 	            case SCIP_VARTYPE_BINARY :
7131 	               cands[c].vartype = 1.0;
7132 	               break;
7133 	            case SCIP_VARTYPE_INTEGER :
7134 	               cands[c].vartype = 0.1;
7135 	               break;
7136 	            case SCIP_VARTYPE_IMPLINT :
7137 	               cands[c].vartype = 0.01;
7138 	               break;
7139 	            case SCIP_VARTYPE_CONTINUOUS :
7140 	            default:
7141 	               cands[c].vartype = 0.0;
7142 	         }
7143 	         maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7144 	      }
7145 	   }
7146 	
7147 	   /* now compute a weighted score for each candidate from the single scores
7148 	    * the single scores are scaled to be in [0,1] for this
7149 	    */
7150 	   for( c = 0; c < ncands; ++c )
7151 	   {
7152 	      SCIP_Real weightsum;
7153 	
7154 	      ENFOLOG(
7155 	         SCIP_VAR* var;
7156 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7157 	         SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7158 	         )
7159 	
7160 	      cands[c].weighted = 0.0;
7161 	      weightsum = 0.0;
7162 	
7163 	      if( maxscore.auxviol > 0.0 )
7164 	      {
7165 	         cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7166 	         weightsum += conshdlrdata->branchviolweight;
7167 	
7168 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7169 	      }
7170 	
7171 	      if( maxscore.domain > 0.0 )
7172 	      {
7173 	         cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7174 	         weightsum += conshdlrdata->branchdomainweight;
7175 	
7176 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7177 	      }
7178 	
7179 	      if( maxscore.dual > 0.0 )
7180 	      {
7181 	         cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7182 	         weightsum += conshdlrdata->branchdualweight;
7183 	
7184 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7185 	      }
7186 	
7187 	      if( maxscore.pscost > 0.0 )
7188 	      {
7189 	         /* use pseudo-costs only if available */
7190 	         if( cands[c].pscost != SCIP_INVALID )
7191 	         {
7192 	            cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7193 	            weightsum += conshdlrdata->branchpscostweight;
7194 	
7195 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7196 	         }
7197 	         else
7198 	         {
7199 	            /* do not add pscostscore, if not available, also do not add into weightsum */
7200 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0*    n/a(pscost)"); )
7201 	         }
7202 	      }
7203 	
7204 	      if( maxscore.vartype > 0.0 )
7205 	      {
7206 	         cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7207 	         weightsum += conshdlrdata->branchvartypeweight;
7208 	
7209 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7210 	      }
7211 	      assert(weightsum > 0.0);  /* we should have got at least one valid score */
7212 	      cands[c].weighted /= weightsum;
7213 	
7214 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7215 	   }
7216 	}
7217 	
7218 	/** compare two branching candidates by their weighted score
7219 	 *
7220 	 * if weighted score is equal, use variable index of (aux)var
7221 	 */
7222 	static
7223 	SCIP_DECL_SORTINDCOMP(branchcandCompare)
7224 	{
7225 	   BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7226 	
7227 	   if( cands[ind1].weighted != cands[ind2].weighted )
7228 	      return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7229 	   else
7230 	      return SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind1].expr)) - SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind2].expr));
7231 	}
7232 	
7233 	/** do branching or register branching candidates */
7234 	static
7235 	SCIP_RETCODE branching(
7236 	   SCIP*                 scip,               /**< SCIP data structure */
7237 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7238 	   SCIP_CONS**           conss,              /**< constraints to process */
7239 	   int                   nconss,             /**< number of constraints */
7240 	   SCIP_Real             maxrelconsviol,     /**< maximal scaled constraint violation */
7241 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
7242 	   SCIP_Longint          soltag,             /**< tag of solution */
7243 	   SCIP_RESULT*          result              /**< pointer to store the result of branching */
7244 	   )
7245 	{
7246 	   SCIP_CONSHDLRDATA* conshdlrdata;
7247 	   BRANCHCAND* cands;
7248 	   int ncands;
7249 	   SCIP_VAR* var;
7250 	   SCIP_NODE* downchild;
7251 	   SCIP_NODE* eqchild;
7252 	   SCIP_NODE* upchild;
7253 	
7254 	   assert(conshdlr != NULL);
7255 	   assert(result != NULL);
7256 	
7257 	   *result = SCIP_DIDNOTFIND;
7258 	
7259 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7260 	   assert(conshdlrdata != NULL);
7261 	
7262 	   if( conshdlrdata->branchexternal )
7263 	   {
7264 	      /* just register branching candidates as external */
7265 	      SCIP_Bool success;
7266 	
7267 	      SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7268 	      if( success )
7269 	         *result = SCIP_INFEASIBLE;
7270 	
7271 	      return SCIP_OKAY;
7272 	   }
7273 	
7274 	   /* collect branching candidates and their auxviol-score */
7275 	   SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip)) );
7276 	   SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7277 	
7278 	   /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7279 	    * we will return here and let the fallbacks in consEnfo() decide how to proceed
7280 	    */
7281 	   if( ncands == 0 )
7282 	      goto TERMINATE;
7283 	
7284 	   if( ncands > 1 )
7285 	   {
7286 	      /* if there are more than one candidate, then compute scores and select */
7287 	      int* perm;
7288 	      int c;
7289 	      int left;
7290 	      int right;
7291 	      SCIP_Real threshold;
7292 	
7293 	      /* compute additional scores on branching candidates and weighted score */
7294 	      scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7295 	
7296 	      /* sort candidates by weighted score */
7297 	      SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7298 	      SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7299 	
7300 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7301 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7302 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7303 	
7304 	      /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score)  candidate */
7305 	      left = 0;
7306 	      right = ncands - 1;
7307 	      threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7308 	      while( left < right )
7309 	      {
7310 	         int mid = (left + right) / 2;
7311 	         if( cands[perm[mid]].weighted >= threshold )
7312 	            left = mid + 1;
7313 	         else
7314 	            right = mid;
7315 	      }
7316 	      assert(left <= ncands);
7317 	
7318 	      if( left < ncands )
7319 	      {
7320 	         if( cands[perm[left]].weighted >= threshold )
7321 	         {
7322 	            assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7323 	            ncands = left + 1;
7324 	         }
7325 	         else
7326 	         {
7327 	            assert(cands[perm[left]].weighted < threshold);
7328 	            ncands = left;
7329 	         }
7330 	      }
7331 	      assert(ncands > 0);
7332 	
7333 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7334 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7335 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7336 	
7337 	      if( ncands > 1 )
7338 	      {
7339 	         /* choose at random from candidates 0..ncands-1 */
7340 	         if( conshdlrdata->branchrandnumgen == NULL )
7341 	         {
7342 	            SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7343 	         }
7344 	         c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7345 	         var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7346 	      }
7347 	      else
7348 	         var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7349 	
7350 	      SCIPfreeBufferArray(scip, &perm);
7351 	   }
7352 	   else
7353 	   {
7354 	      var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7355 	   }
7356 	   assert(var != NULL);
7357 	
7358 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7359 	            SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); )
7360 	
7361 	   SCIP_CALL( SCIPbranchVarVal(scip, var, SCIPgetBranchingPoint(scip, var, SCIP_INVALID), &downchild, &eqchild,
7362 	            &upchild) );
7363 	   if( downchild != NULL || eqchild != NULL || upchild != NULL )
7364 	      *result = SCIP_BRANCHED;
7365 	   else
7366 	      /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7367 	      *result = SCIP_REDUCEDDOM;
7368 	
7369 	 TERMINATE:
7370 	   SCIPfreeBufferArray(scip, &cands);
7371 	
7372 	   return SCIP_OKAY;
7373 	}
7374 	
7375 	/** call enforcement or estimate callback of nonlinear handler
7376 	 *
7377 	 * Calls the enforcement callback, if available.
7378 	 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7379 	 *
7380 	 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7381 	 */
7382 	static
7383 	SCIP_RETCODE enforceExprNlhdlr(
7384 	   SCIP*                 scip,               /**< SCIP main data structure */
7385 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7386 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
7387 	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
7388 	   SCIP_EXPR*            expr,               /**< expression */
7389 	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata,     /**< nonlinear handler data of expression */
7390 	   SCIP_SOL*             sol,                /**< solution to be separated (NULL for the LP solution) */
7391 	   SCIP_Real             auxvalue,           /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7392 	   SCIP_Bool             overestimate,       /**< whether the expression needs to be over- or underestimated */
7393 	   SCIP_Bool             separated,          /**< whether another nonlinear handler already added a cut for this expression */
7394 	   SCIP_Bool             allowweakcuts,      /**< whether we allow for weak cuts */
7395 	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement (and not just separation) */
7396 	   SCIP_RESULT*          result              /**< pointer to store the result */
7397 	   )
7398 	{
7399 	   assert(result != NULL);
7400 	
7401 	   /* call enforcement callback of the nlhdlr */
7402 	   SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7403 	            allowweakcuts, separated, inenforcement, result) );
7404 	
7405 	   /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7406 	   if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7407 	   {
7408 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    sepa of nlhdlr %s succeeded with result %d\n",
7409 	               SCIPnlhdlrGetName(nlhdlr), *result); )
7410 	      return SCIP_OKAY;
7411 	   }
7412 	   else
7413 	   {
7414 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    sepa of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7415 	   }
7416 	
7417 	   *result = SCIP_DIDNOTFIND;
7418 	
7419 	   /* now call the estimator callback of the nlhdlr */
7420 	   if( SCIPnlhdlrHasEstimate(nlhdlr) )
7421 	   {
7422 	      SCIP_VAR* auxvar;
7423 	      SCIP_Bool sepasuccess = FALSE;
7424 	      SCIP_Bool branchscoresuccess = FALSE;
7425 	      SCIP_PTRARRAY* rowpreps;
7426 	      int minidx;
7427 	      int maxidx;
7428 	      int r;
7429 	      SCIP_ROWPREP* rowprep;
7430 	
7431 	      SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7432 	
7433 	      auxvar = SCIPgetExprAuxVarNonlinear(expr);
7434 	      assert(auxvar != NULL);
7435 	
7436 	      SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7437 	               SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7438 	
7439 	      minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7440 	      maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7441 	
7442 	      assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7443 	
7444 	      if( !sepasuccess )
7445 	      {
7446 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s failed\n",
7447 	                  SCIPnlhdlrGetName(nlhdlr)); )
7448 	      }
7449 	
7450 	      for( r = minidx; r <= maxidx; ++r )
7451 	      {
7452 	         rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7453 	
7454 	         assert(rowprep != NULL);
7455 	         assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7456 	
7457 	         /* complete estimator to cut */
7458 	         SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7459 	
7460 	         /* add the cut and/or branching scores */
7461 	         SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7462 	               auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7463 	
7464 	         SCIPfreeRowprep(scip, &rowprep);
7465 	      }
7466 	
7467 	      SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7468 	   }
7469 	
7470 	   return SCIP_OKAY;
7471 	}
7472 	
7473 	/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7474 	 *
7475 	 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7476 	 */
7477 	static
7478 	SCIP_RETCODE enforceExpr(
7479 	   SCIP*                 scip,               /**< SCIP data structure */
7480 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
7481 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
7482 	   SCIP_EXPR*            expr,               /**< expression */
7483 	   SCIP_SOL*             sol,                /**< solution to separate, or NULL if LP solution should be used */
7484 	   SCIP_Longint          soltag,             /**< tag of solution */
7485 	   SCIP_Bool             allowweakcuts,      /**< whether we allow weak cuts */
7486 	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement (and not just separation) */
7487 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
7488 	   )
7489 	{
7490 	   SCIP_CONSHDLRDATA* conshdlrdata;
7491 	   SCIP_EXPR_OWNERDATA* ownerdata;
7492 	   SCIP_Real origviol;
7493 	   SCIP_Bool underestimate;
7494 	   SCIP_Bool overestimate;
7495 	   SCIP_Real auxviol;
7496 	   SCIP_Bool auxunderestimate;
7497 	   SCIP_Bool auxoverestimate;
7498 	   SCIP_RESULT hdlrresult;
7499 	   int e;
7500 	
7501 	   assert(scip != NULL);
7502 	   assert(expr != NULL);
7503 	   assert(result != NULL);
7504 	
7505 	   ownerdata = SCIPexprGetOwnerData(expr);
7506 	   assert(ownerdata != NULL);
7507 	   assert(ownerdata->auxvar != NULL);  /* there must be a variable attached to the expression in order to construct a cut here */
7508 	
7509 	   *result = SCIP_DIDNOTFIND;
7510 	
7511 	   /* make sure that this expression has been evaluated */
7512 	   SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7513 	
7514 	   /* decide whether under- or overestimate is required and get amount of violation */
7515 	   origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7516 	
7517 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7518 	   assert(conshdlrdata != NULL);
7519 	
7520 	   /* no sufficient violation w.r.t. the original variables -> skip expression */
7521 	   if( !overestimate && !underestimate )
7522 	   {
7523 	      return SCIP_OKAY;
7524 	   }
7525 	
7526 	   /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7527 	   for( e = 0; e < ownerdata->nenfos; ++e )
7528 	   {
7529 	      SCIP_NLHDLR* nlhdlr;
7530 	
7531 	      /* skip nlhdlr that do not want to participate in any separation */
7532 	      if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7533 	         continue;
7534 	
7535 	      nlhdlr = ownerdata->enfos[e]->nlhdlr;
7536 	      assert(nlhdlr != NULL);
7537 	
7538 	      /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7539 	      SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7540 	      ENFOLOG(
7541 	         SCIPinfoMessage(scip, enfologfile, "  expr ");
7542 	         SCIPprintExpr(scip, expr, enfologfile);
7543 	         SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7544 	            "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7545 	            SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7546 	      )
7547 	
7548 	      /* TODO if expr is root of constraint (consdata->expr == expr),
7549 	       * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7550 	       * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7551 	       * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7552 	       * so we should enforce in these auxiliaries first
7553 	       * if changing this here, we must also adapt analyzeViolation()
7554 	       */
7555 	
7556 	      auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7557 	      assert(auxviol >= 0.0);
7558 	
7559 	      /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7560 	      if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7561 	      {
7562 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7563 	                  "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7564 	                  SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7565 	
7566 	         /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7567 	         continue;
7568 	      }
7569 	
7570 	      /* 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 */
7571 	      if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7572 	      {
7573 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7574 	                  "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7575 	                  underestimate, overestimate); )
7576 	
7577 	            /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7578 	         continue;
7579 	      }
7580 	
7581 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7582 	               "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7583 	               auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7584 	
7585 	      /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7586 	       * wants to be called for separation on this side, then call separation of nlhdlr
7587 	       */
7588 	      if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7589 	      {
7590 	         /* call the separation or estimation callback of the nonlinear handler for overestimation */
7591 	         hdlrresult = SCIP_DIDNOTFIND;
7592 	         SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7593 	            ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7594 	
7595 	         if( hdlrresult == SCIP_CUTOFF )
7596 	         {
7597 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    found a cutoff -> stop separation\n"); )
7598 	            *result = SCIP_CUTOFF;
7599 	            ownerdata->lastenforced = conshdlrdata->enforound;
7600 	            break;
7601 	         }
7602 	
7603 	         if( hdlrresult == SCIP_SEPARATED )
7604 	         {
7605 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7606 	            *result = SCIP_SEPARATED;
7607 	            ownerdata->lastenforced = conshdlrdata->enforound;
7608 	            /* TODO or should we give other nlhdlr another chance? (also #3070) */
7609 	            break;
7610 	         }
7611 	
7612 	         if( hdlrresult == SCIP_REDUCEDDOM )
7613 	         {
7614 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7615 	            *result = SCIP_REDUCEDDOM;
7616 	            ownerdata->lastenforced = conshdlrdata->enforound;
7617 	            /* TODO or should we always just stop here? */
7618 	         }
7619 	
7620 	         if( hdlrresult == SCIP_BRANCHED )
7621 	         {
7622 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7623 	            assert(inenforcement);
7624 	
7625 	            /* separation and domain reduction takes precedence over branching */
7626 	            assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7627 	            if( *result == SCIP_DIDNOTFIND )
7628 	               *result = SCIP_BRANCHED;
7629 	            ownerdata->lastenforced = conshdlrdata->enforound;
7630 	         }
7631 	      }
7632 	
7633 	      /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7634 	       * wants to be called for separation on this side, then call separation of nlhdlr
7635 	       */
7636 	      if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7637 	      {
7638 	         /* call the separation or estimation callback of the nonlinear handler for underestimation */
7639 	         hdlrresult = SCIP_DIDNOTFIND;
7640 	         SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7641 	            ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7642 	
7643 	         if( hdlrresult == SCIP_CUTOFF )
7644 	         {
7645 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    found a cutoff -> stop separation\n"); )
7646 	            *result = SCIP_CUTOFF;
7647 	            ownerdata->lastenforced = conshdlrdata->enforound;
7648 	            break;
7649 	         }
7650 	
7651 	         if( hdlrresult == SCIP_SEPARATED )
7652 	         {
7653 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7654 	            *result = SCIP_SEPARATED;
7655 	            ownerdata->lastenforced = conshdlrdata->enforound;
7656 	            /* TODO or should we give other nlhdlr another chance? (also #3070) */
7657 	            break;
7658 	         }
7659 	
7660 	         if( hdlrresult == SCIP_REDUCEDDOM )
7661 	         {
7662 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7663 	            *result = SCIP_REDUCEDDOM;
7664 	            ownerdata->lastenforced = conshdlrdata->enforound;
7665 	            /* TODO or should we always just stop here? */
7666 	         }
7667 	
7668 	         if( hdlrresult == SCIP_BRANCHED )
7669 	         {
7670 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7671 	            assert(inenforcement);
7672 	
7673 	            /* separation takes precedence over branching */
7674 	            assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7675 	            if( *result == SCIP_DIDNOTFIND )
7676 	               *result = SCIP_BRANCHED;
7677 	            ownerdata->lastenforced = conshdlrdata->enforound;
7678 	         }
7679 	      }
7680 	   }
7681 	
7682 	   return SCIP_OKAY;
7683 	}
7684 	
7685 	/** helper function to enforce a single constraint */
7686 	static
7687 	SCIP_RETCODE enforceConstraint(
7688 	   SCIP*                 scip,               /**< SCIP data structure */
7689 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7690 	   SCIP_CONS*            cons,               /**< constraint to process */
7691 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
7692 	   SCIP_Longint          soltag,             /**< tag of solution */
7693 	   SCIP_EXPRITER*        it,                 /**< expression iterator that we can just use here */
7694 	   SCIP_Bool             allowweakcuts,      /**< whether to allow weak cuts in this round */
7695 	   SCIP_Bool             inenforcement,      /**< whether to we are in enforcement, and not just separation */
7696 	   SCIP_RESULT*          result,             /**< pointer to update with result of the enforcing call */
7697 	   SCIP_Bool*            success             /**< buffer to store whether some enforcement took place */
7698 	   )
7699 	{
7700 	   SCIP_CONSDATA* consdata;
7701 	   SCIP_CONSHDLRDATA* conshdlrdata;
7702 	   SCIP_EXPR* expr;
7703 	
7704 	   assert(conshdlr != NULL);
7705 	   assert(cons != NULL);
7706 	   assert(it != NULL);
7707 	   assert(result != NULL);
7708 	   assert(success != NULL);
7709 	
7710 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7711 	   assert(conshdlrdata != NULL);
7712 	
7713 	   consdata = SCIPconsGetData(cons);
7714 	   assert(consdata != NULL);
7715 	   assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7716 	
7717 	   *success = FALSE;
7718 	
7719 	   if( inenforcement && !consdata->ispropagated )
7720 	   {
7721 	      /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7722 	       * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7723 	       * (TODO: nlhdlr tells us now whether they do and so we could skip).
7724 	       * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7725 	       * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7726 	       * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7727 	       * confuse the stalling check for how long to do separation).
7728 	       */
7729 	      SCIP_Bool infeasible;
7730 	      int ntightenings;
7731 	
7732 	      SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7733 	      if( infeasible )
7734 	      {
7735 	         *result = SCIP_CUTOFF;
7736 	         return SCIP_OKAY;
7737 	      }
7738 	      /* if we tightened an auxvar bound, we better communicate that */
7739 	      if( ntightenings > 0 )
7740 	         *result = SCIP_REDUCEDDOM;
7741 	   }
7742 	
7743 	   for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7744 	   {
7745 	      SCIP_EXPR_OWNERDATA* ownerdata;
7746 	      SCIP_RESULT resultexpr;
7747 	
7748 	      ownerdata = SCIPexprGetOwnerData(expr);
7749 	      assert(ownerdata != NULL);
7750 	
7751 	      /* we can only enforce if there is an auxvar to compare with */
7752 	      if( ownerdata->auxvar == NULL )
7753 	         continue;
7754 	
7755 	      assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7756 	      if( ownerdata->lastenforced == conshdlrdata->enforound )
7757 	      {
7758 	         ENFOLOG(
7759 	            SCIPinfoMessage(scip, enfologfile, "  skip expr ");
7760 	            SCIPprintExpr(scip, expr, enfologfile);
7761 	            SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7762 	         )
7763 	         *success = TRUE;
7764 	         continue;
7765 	      }
7766 	
7767 	      SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7768 	
7769 	      /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7770 	      assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7771 	      if( ownerdata->lastenforced == conshdlrdata->enforound )
7772 	         *success = TRUE;
7773 	
7774 	      if( resultexpr == SCIP_CUTOFF )
7775 	      {
7776 	         *result = SCIP_CUTOFF;
7777 	         break;
7778 	      }
7779 	
7780 	      if( resultexpr == SCIP_SEPARATED )
7781 	         *result = SCIP_SEPARATED;
7782 	
7783 	      if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7784 	         *result = SCIP_REDUCEDDOM;
7785 	
7786 	      if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7787 	         *result = SCIP_BRANCHED;
7788 	   }
7789 	
7790 	   return SCIP_OKAY;
7791 	}
7792 	
7793 	/** try to separate violated constraints and, if in enforcement, register branching scores
7794 	 *
7795 	 * Sets result to
7796 	 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7797 	 * - SCIP_CUTOFF, if node can be cutoff,
7798 	 * - SCIP_SEPARATED, if a cut has been added,
7799 	 * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7800 	 * - SCIP_BRANCHED, if branching has been done,
7801 	 * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7802 	 * - SCIP_INFEASIBLE, if external branching candidates were registered
7803 	 */
7804 	static
7805 	SCIP_RETCODE enforceConstraints(
7806 	   SCIP*                 scip,               /**< SCIP data structure */
7807 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7808 	   SCIP_CONS**           conss,              /**< constraints to process */
7809 	   int                   nconss,             /**< number of constraints */
7810 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
7811 	   SCIP_Longint          soltag,             /**< tag of solution */
7812 	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement, and not just separation */
7813 	   SCIP_Real             maxrelconsviol,     /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7814 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
7815 	   )
7816 	{
7817 	   SCIP_CONSHDLRDATA* conshdlrdata;
7818 	   SCIP_EXPRITER* it;
7819 	   SCIP_Bool consenforced;  /* whether any expression in constraint could be enforced */
7820 	   int c;
7821 	
7822 	   assert(conshdlr != NULL);
7823 	   assert(conss != NULL || nconss == 0);
7824 	   assert(result != NULL);
7825 	
7826 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7827 	   assert(conshdlrdata != NULL);
7828 	
7829 	   /* increase tag to tell whether branching scores in expression belong to this sweep
7830 	    * and which expressions have already been enforced in this sweep
7831 	    * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7832 	    */
7833 	   ++(conshdlrdata->enforound);
7834 	
7835 	   *result = SCIP_DIDNOTFIND;
7836 	
7837 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7838 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, TRUE) );
7839 	
7840 	   for( c = 0; c < nconss; ++c )
7841 	   {
7842 	      assert(conss != NULL && conss[c] != NULL);
7843 	
7844 	      /* skip constraints that are not enabled or deleted */
7845 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7846 	         continue;
7847 	      assert(SCIPconsIsActive(conss[c]));
7848 	
7849 	      /* skip constraints that have separation disabled if we are only in separation */
7850 	      if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7851 	         continue;
7852 	
7853 	      /* skip non-violated constraints */
7854 	      if( !isConsViolated(scip, conss[c]) )
7855 	         continue;
7856 	
7857 	      ENFOLOG(
7858 	      {
7859 	         SCIP_CONSDATA* consdata;
7860 	         int i;
7861 	         consdata = SCIPconsGetData(conss[c]);
7862 	         assert(consdata != NULL);
7863 	         SCIPinfoMessage(scip, enfologfile, " constraint ");
7864 	         SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7865 	         SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7866 	         for( i = 0; i < consdata->nvarexprs; ++i )
7867 	         {
7868 	            SCIP_VAR* var;
7869 	            var = SCIPgetVarExprVar(consdata->varexprs[i]);
7870 	            SCIPinfoMessage(scip, enfologfile, "  %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7871 	                  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7872 	         }
7873 	      })
7874 	
7875 	      SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, result, &consenforced) );
7876 	
7877 	      if( *result == SCIP_CUTOFF )
7878 	         break;
7879 	
7880 	      if( !consenforced && inenforcement )
7881 	      {
7882 	         SCIP_Real viol;
7883 	
7884 	         SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7885 	         if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7886 	         {
7887 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7888 	                     "cuts allowed\n", SCIPconsGetName(conss[c])); )
7889 	
7890 	            SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, result, &consenforced) );
7891 	
7892 	            if( consenforced )
7893 	               ++conshdlrdata->nweaksepa;  /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7894 	
7895 	            if( *result == SCIP_CUTOFF )
7896 	               break;
7897 	         }
7898 	      }
7899 	   }
7900 	
7901 	   SCIPfreeExpriter(&it);
7902 	
7903 	   ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7904 	
7905 	   /* if having branching scores, then propagate them from expressions with children to variable expressions */
7906 	   if( *result == SCIP_BRANCHED )
7907 	   {
7908 	      /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7909 	       * branching
7910 	       */
7911 	      SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7912 	
7913 	      /* branching should either have branched: result == SCIP_BRANCHED,
7914 	       * or fixed a variable: result == SCIP_REDUCEDDOM,
7915 	       * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7916 	       * or have not done anything: result == SCIP_DIDNOTFIND
7917 	       */
7918 	      assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7919 	   }
7920 	
7921 	   ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7922 	
7923 	   return SCIP_OKAY;
7924 	}
7925 	
7926 	/** collect (and print (if debugging enfo)) information on violation in expressions
7927 	 *
7928 	 * assumes that constraint violations have been computed
7929 	 */
7930 	static
7931 	SCIP_RETCODE analyzeViolation(
7932 	   SCIP*                 scip,               /**< SCIP data structure */
7933 	   SCIP_CONS**           conss,              /**< constraints */
7934 	   int                   nconss,             /**< number of constraints */
7935 	   SCIP_SOL*             sol,                /**< solution to separate, or NULL if LP solution should be used */
7936 	   SCIP_Longint          soltag,             /**< tag of solution */
7937 	   SCIP_Real*            maxabsconsviol,     /**< buffer to store maximal absolute violation of constraints */
7938 	   SCIP_Real*            maxrelconsviol,     /**< buffer to store maximal relative violation of constraints */
7939 	   SCIP_Real*            minauxviol,         /**< buffer to store minimal (nonzero) violation of auxiliaries */
7940 	   SCIP_Real*            maxauxviol,         /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7941 	   SCIP_Real*            maxvarboundviol     /**< buffer to store maximal violation of variable bounds */
7942 	   )
7943 	{
7944 	   SCIP_CONSDATA* consdata;
7945 	   SCIP_EXPRITER* it;
7946 	   SCIP_EXPR* expr;
7947 	   SCIP_Real v;
7948 	   int c;
7949 	
7950 	   assert(conss != NULL || nconss == 0);
7951 	   assert(maxabsconsviol != NULL);
7952 	   assert(maxrelconsviol != NULL);
7953 	   assert(maxauxviol != NULL);
7954 	   assert(maxvarboundviol != NULL);
7955 	
7956 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7957 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
7958 	
7959 	   *maxabsconsviol = 0.0;
7960 	   *maxrelconsviol = 0.0;
7961 	   *minauxviol = SCIPinfinity(scip);
7962 	   *maxauxviol = 0.0;
7963 	   *maxvarboundviol = 0.0;
7964 	
7965 	   for( c = 0; c < nconss; ++c )
7966 	   {
7967 	      assert(conss != NULL && conss[c] != NULL);
7968 	
7969 	      consdata = SCIPconsGetData(conss[c]);
7970 	      assert(consdata != NULL);
7971 	
7972 	      /* skip constraints that are not enabled, deleted, or have separation disabled */
7973 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7974 	         continue;
7975 	      assert(SCIPconsIsActive(conss[c]));
7976 	
7977 	      v = getConsAbsViolation(conss[c]);
7978 	      *maxabsconsviol = MAX(*maxabsconsviol, v);
7979 	
7980 	      /* skip non-violated constraints */
7981 	      if( !isConsViolated(scip, conss[c]) )
7982 	         continue;
7983 	
7984 	      SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
7985 	      *maxrelconsviol = MAX(*maxrelconsviol, v);
7986 	
7987 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7988 	      {
7989 	         SCIP_EXPR_OWNERDATA* ownerdata;
7990 	         SCIP_Real auxvarvalue;
7991 	         SCIP_Real auxvarlb;
7992 	         SCIP_Real auxvarub;
7993 	         SCIP_Bool violunder;
7994 	         SCIP_Bool violover;
7995 	         SCIP_Real origviol;
7996 	         SCIP_Real auxviol;
7997 	         int e;
7998 	
7999 	         ownerdata = SCIPexprGetOwnerData(expr);
8000 	         assert(ownerdata != NULL);
8001 	
8002 	         if( ownerdata->auxvar == NULL )
8003 	         {
8004 	            /* check violation of variable bounds of original variable */
8005 	            if( SCIPisExprVar(scip, expr) )
8006 	            {
8007 	               SCIP_VAR* var;
8008 	               var = SCIPgetVarExprVar(expr);
8009 	               auxvarvalue = SCIPgetSolVal(scip, sol, var);
8010 	               auxvarlb = SCIPvarGetLbLocal(var);
8011 	               auxvarub = SCIPvarGetUbLocal(var);
8012 	
8013 	               origviol = 0.0;
8014 	               if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8015 	                  origviol = auxvarlb - auxvarvalue;
8016 	               else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8017 	                  origviol = auxvarvalue - auxvarub;
8018 	               if( origviol <= 0.0 )
8019 	                  continue;
8020 	
8021 	               *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8022 	
8023 	               ENFOLOG(
8024 	               SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8025 	               if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8026 	                  SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8027 	               if( auxvarub < auxvarvalue && !SCIPisInfinity(scip,  auxvarub) )
8028 	                  SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8029 	               SCIPinfoMessage(scip, enfologfile, "\n");
8030 	               )
8031 	            }
8032 	
8033 	            continue;
8034 	         }
8035 	
8036 	         auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8037 	         auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8038 	         auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8039 	
8040 	         /* check violation of variable bounds of auxiliary variable */
8041 	         if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8042 	            *maxvarboundviol = auxvarlb - auxvarvalue;
8043 	         else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip,  auxvarub) )
8044 	            *maxvarboundviol = auxvarvalue - auxvarub;
8045 	
8046 	         origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8047 	
8048 	         ENFOLOG(
8049 	         if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8050 	         {
8051 	            SCIPinfoMessage(scip, enfologfile, "expr ");
8052 	            SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8053 	            SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8054 	
8055 	            SCIPinfoMessage(scip, enfologfile, "  auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8056 	            if( origviol > 0.0 )
8057 	               SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8058 	            if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8059 	               SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8060 	            if( auxvarub < auxvarvalue && !SCIPisInfinity(scip,  auxvarub) )
8061 	               SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8062 	            SCIPinfoMessage(scip, enfologfile, "\n");
8063 	         }
8064 	         )
8065 	
8066 	         /* no violation w.r.t. the original variables -> skip expression */
8067 	         if( origviol == 0.0 )
8068 	            continue;
8069 	
8070 	         /* compute aux-violation for each nonlinear handlers */
8071 	         for( e = 0; e < ownerdata->nenfos; ++e )
8072 	         {
8073 	            SCIP_NLHDLR* nlhdlr;
8074 	
8075 	            /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8076 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8077 	               continue;
8078 	
8079 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
8080 	            assert(nlhdlr != NULL);
8081 	
8082 	            /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8083 	            SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8084 	
8085 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "  nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8086 	
8087 	            auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8088 	
8089 	            if( auxviol > 0.0 )
8090 	            {
8091 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8092 	               *maxauxviol = MAX(*maxauxviol, auxviol);
8093 	               *minauxviol = MIN(*minauxviol, auxviol);
8094 	            }
8095 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8096 	         }
8097 	      }
8098 	   }
8099 	
8100 	   SCIPfreeExpriter(&it);
8101 	
8102 	   return SCIP_OKAY;
8103 	} /*lint !e715*/
8104 	
8105 	/** enforcement of constraints called by enfolp and enforelax */
8106 	static
8107 	SCIP_RETCODE consEnfo(
8108 	   SCIP*                 scip,               /**< SCIP data structure */
8109 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
8110 	   SCIP_CONS**           conss,              /**< constraints to process */
8111 	   int                   nconss,             /**< number of constraints */
8112 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
8113 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
8114 	   )
8115 	{
8116 	   SCIP_CONSHDLRDATA* conshdlrdata;
8117 	   SCIP_Real maxabsconsviol;
8118 	   SCIP_Real maxrelconsviol;
8119 	   SCIP_Real minauxviol;
8120 	   SCIP_Real maxauxviol;
8121 	   SCIP_Real maxvarboundviol;
8122 	   SCIP_Longint soltag;
8123 	   int nnotify;
8124 	   int c;
8125 	
8126 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8127 	   assert(conshdlr != NULL);
8128 	
8129 	   soltag = SCIPgetExprNewSoltag(scip);
8130 	
8131 	   *result = SCIP_FEASIBLE;
8132 	   for( c = 0; c < nconss; ++c )
8133 	   {
8134 	      SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8135 	
8136 	      if( isConsViolated(scip, conss[c]) )
8137 	         *result = SCIP_INFEASIBLE;
8138 	   }
8139 	
8140 	   if( *result == SCIP_FEASIBLE )
8141 	   {
8142 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8143 	               SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8144 	      return SCIP_OKAY;
8145 	   }
8146 	
8147 	   SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8148 	            &minauxviol, &maxauxviol, &maxvarboundviol) );
8149 	
8150 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8151 	            "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8152 	            SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8153 	            maxvarboundviol, SCIPgetLPFeastol(scip)); )
8154 	
8155 	   assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8156 	
8157 	   /* try to propagate */
8158 	   if( conshdlrdata->propinenforce )
8159 	   {
8160 	      SCIP_RESULT propresult;
8161 	      int nchgbds = 0;
8162 	
8163 	      SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8164 	
8165 	      if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8166 	      {
8167 	         *result = propresult;
8168 	         return SCIP_OKAY;
8169 	      }
8170 	   }
8171 	
8172 	   /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8173 	    * all violated expr/auxvar in violated constraints)
8174 	    */
8175 	   if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8176 	         sol == NULL )
8177 	   {
8178 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8179 	      ++conshdlrdata->ntightenlp;
8180 	
8181 	      *result = SCIP_SOLVELP;
8182 	
8183 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8184 	               "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8185 	
8186 	      return SCIP_OKAY;
8187 	   }
8188 	
8189 	   /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8190 	    * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8191 	    */
8192 	   if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8193 	   {
8194 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8195 	      ++conshdlrdata->ntightenlp;
8196 	
8197 	      *result = SCIP_SOLVELP;
8198 	
8199 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8200 	
8201 	      return SCIP_OKAY;
8202 	   }
8203 	
8204 	   SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8205 	
8206 	   if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8207 	         *result == SCIP_INFEASIBLE )
8208 	      return SCIP_OKAY;
8209 	
8210 	   assert(*result == SCIP_DIDNOTFIND);
8211 	
8212 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8213 	            "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8214 	
8215 	   if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8216 	   {
8217 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8218 	      ++conshdlrdata->ntightenlp;
8219 	
8220 	      *result = SCIP_SOLVELP;
8221 	
8222 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8223 	               "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8224 	
8225 	      return SCIP_OKAY;
8226 	   }
8227 	
8228 	   if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8229 	            SCIPgetLPFeastol(scip)) && sol == NULL )
8230 	   {
8231 	      /* try whether tighten the LP feasibility tolerance could help
8232 	       * maybe it is just some cut that hasn't been taken into account sufficiently
8233 	       * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8234 	       * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8235 	       * until the LP feastol reaches epsilon
8236 	       * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8237 	       * when maxauxviol is above LP feastol)
8238 	       */
8239 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8240 	      ++conshdlrdata->ndesperatetightenlp;
8241 	
8242 	      *result = SCIP_SOLVELP;
8243 	
8244 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8245 	
8246 	      return SCIP_OKAY;
8247 	   }
8248 	
8249 	   /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8250 	   if( !conshdlrdata->propinenforce )
8251 	   {
8252 	      SCIP_RESULT propresult;
8253 	      int nchgbds = 0;
8254 	
8255 	      SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8256 	
8257 	      if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8258 	      {
8259 	         *result = propresult;
8260 	         return SCIP_OKAY;
8261 	      }
8262 	   }
8263 	
8264 	   /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8265 	    * now look if we find any unfixed variable that we could still branch on
8266 	    */
8267 	   SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8268 	
8269 	   if( nnotify > 0 )
8270 	   {
8271 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8272 	      ++conshdlrdata->ndesperatebranch;
8273 	
8274 	      *result = SCIP_INFEASIBLE;  /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8275 	
8276 	      return SCIP_OKAY;
8277 	   }
8278 	
8279 	   /* if everything is fixed in violated constraints, then let's cut off the node
8280 	    * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8281 	    *   result may not be conclusive (when constraint violations are small)
8282 	    * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8283 	    *   sufficiently (see st_e40)
8284 	    * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8285 	    *   not "desperate", but a pretty obvious thing to do
8286 	    */
8287 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8288 	   *result = SCIP_CUTOFF;
8289 	
8290 	   /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8291 	   if( !SCIPisZero(scip, maxvarboundviol) )
8292 	      ++conshdlrdata->ndesperatecutoff;
8293 	
8294 	   return SCIP_OKAY;
8295 	}
8296 	
8297 	/** separation for all violated constraints to be used by SEPA callbacks */
8298 	static
8299 	SCIP_RETCODE consSepa(
8300 	   SCIP*                 scip,               /**< SCIP data structure */
8301 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
8302 	   SCIP_CONS**           conss,              /**< constraints to process */
8303 	   int                   nconss,             /**< number of constraints */
8304 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
8305 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
8306 	   )
8307 	{
8308 	   SCIP_Longint soltag;
8309 	   SCIP_Bool haveviol = FALSE;
8310 	   int c;
8311 	
8312 	   *result = SCIP_DIDNOTFIND;
8313 	
8314 	   soltag = SCIPgetExprNewSoltag(scip);
8315 	
8316 	   /* compute violations */
8317 	   for( c = 0; c < nconss; ++c )
8318 	   {
8319 	      assert(conss[c] != NULL);
8320 	
8321 	      /* skip constraints that are not enabled, deleted, or have separation disabled */
8322 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8323 	         continue;
8324 	      assert(SCIPconsIsActive(conss[c]));
8325 	
8326 	      SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8327 	
8328 	      if( isConsViolated(scip, conss[c]) )
8329 	         haveviol = TRUE;
8330 	   }
8331 	
8332 	   /* if none of our constraints are violated, don't attempt separation */
8333 	   if( !haveviol )
8334 	   {
8335 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8336 	      return SCIP_OKAY;
8337 	   }
8338 	
8339 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8340 	
8341 	   /* call separation */
8342 	   SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8343 	
8344 	   return SCIP_OKAY;
8345 	}
8346 	
8347 	/** hash key retrieval function for bilinear term entries */
8348 	static
8349 	SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8350 	{  /*lint --e{715}*/
8351 	   SCIP_CONSHDLRDATA* conshdlrdata;
8352 	   int idx;
8353 	
8354 	   conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8355 	   assert(conshdlrdata != NULL);
8356 	
8357 	   idx = ((int)(size_t)elem) - 1;
8358 	   assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8359 	
8360 	   return (void*)&conshdlrdata->bilinterms[idx];
8361 	}
8362 	
8363 	/** returns TRUE iff the bilinear term entries are equal */
8364 	static
8365 	SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8366 	{  /*lint --e{715}*/
8367 	   SCIP_CONSNONLINEAR_BILINTERM* entry1;
8368 	   SCIP_CONSNONLINEAR_BILINTERM* entry2;
8369 	
8370 	   /* get corresponding entries */
8371 	   entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8372 	   entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8373 	   assert(entry1->x != NULL && entry1->y != NULL);
8374 	   assert(entry2->x != NULL && entry2->y != NULL);
8375 	   assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8376 	   assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8377 	
8378 	   return entry1->x == entry2->x && entry1->y == entry2->y;
8379 	}
8380 	
8381 	/** returns the hash value of the key */
8382 	static
8383 	SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8384 	{  /*lint --e{715}*/
8385 	   SCIP_CONSNONLINEAR_BILINTERM* entry;
8386 	
8387 	   entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8388 	   assert(entry->x != NULL && entry->y != NULL);
8389 	   assert(SCIPvarCompare(entry->x, entry->y) < 1);
8390 	
8391 	   return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8392 	}
8393 	
8394 	/** compare two auxiliary expressions
8395 	 *
8396 	 *  Compares auxiliary variables, followed by coefficients, and then constants.
8397 	 */
8398 	static
8399 	SCIP_DECL_SORTPTRCOMP(auxexprComp)
8400 	{
8401 	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr1 = (SCIP_CONSNONLINEAR_AUXEXPR*)elem1;
8402 	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr2 = (SCIP_CONSNONLINEAR_AUXEXPR*)elem2;
8403 	   int compvars;
8404 	   int i;
8405 	
8406 	   /* compare the auxiliary variables */
8407 	   compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8408 	
8409 	   if( compvars != 0 )
8410 	      return compvars;
8411 	
8412 	   /* compare the coefficients and constants */
8413 	   for( i = 0; i < 3; ++i )
8414 	   {
8415 	      if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8416 	         return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8417 	   }
8418 	
8419 	   return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8420 	}
8421 	
8422 	/* add an auxiliary expression to a bilinear term */
8423 	static
8424 	SCIP_RETCODE bilinTermAddAuxExpr(
8425 	   SCIP*                 scip,               /**< SCIP data structure */
8426 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< nonlinear constraint handler data */
8427 	   SCIP_CONSNONLINEAR_BILINTERM* term,       /**< bilinear term */
8428 	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr,      /**< auxiliary expression to add */
8429 	   SCIP_Bool*            added               /**< pointer to store whether auxexpr has been added */
8430 	   )
8431 	{
8432 	   SCIP_Bool found;
8433 	   int pos;
8434 	   int i;
8435 	
8436 	   *added = FALSE;
8437 	
8438 	   /* check if auxexpr has already been added to term */
8439 	   if( term->nauxexprs == 0 )
8440 	   {
8441 	      found = FALSE;
8442 	      pos = 0;
8443 	   }
8444 	   else
8445 	   {
8446 	      found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8447 	   }
8448 	
8449 	   if( !found )
8450 	   {
8451 	      if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8452 	         return SCIP_OKAY;
8453 	
8454 	      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8455 	      assert(term->auxexprssize >= term->nauxexprs + 1);
8456 	
8457 	      /* insert expression at the correct position */
8458 	      for( i = term->nauxexprs; i > pos; --i )
8459 	      {
8460 	         term->aux.exprs[i] = term->aux.exprs[i-1];
8461 	      }
8462 	      term->aux.exprs[pos] = auxexpr;
8463 	      ++(term->nauxexprs);
8464 	      *added = TRUE;
8465 	   }
8466 	   else
8467 	   {
8468 	      term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8469 	      term->aux.exprs[pos]->overestimate  |= auxexpr->overestimate;
8470 	   }
8471 	
8472 	   return SCIP_OKAY;
8473 	}
8474 	
8475 	/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8476 	static
8477 	SCIP_RETCODE bilinearTermsInsertAll(
8478 	   SCIP*                 scip,               /**< SCIP data structure */
8479 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
8480 	   SCIP_CONS**           conss,              /**< nonlinear constraints */
8481 	   int                   nconss              /**< total number of nonlinear constraints */
8482 	   )
8483 	{
8484 	   SCIP_CONSHDLRDATA* conshdlrdata;
8485 	   SCIP_EXPRITER* it;
8486 	   int c;
8487 	
8488 	   assert(conss != NULL || nconss == 0);
8489 	
8490 	   if( nconss == 0 )
8491 	      return SCIP_OKAY;
8492 	
8493 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8494 	   assert(conshdlrdata != NULL);
8495 	
8496 	   /* check whether the bilinear terms have been stored already */
8497 	   if( conshdlrdata->bilinterms != NULL )
8498 	      return SCIP_OKAY;
8499 	
8500 	   /* create and initialize iterator */
8501 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8502 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
8503 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR);
8504 	
8505 	   /* iterate through all constraints */
8506 	   for( c = 0; c < nconss; ++c )
8507 	   {
8508 	      SCIP_CONSDATA* consdata;
8509 	      SCIP_EXPR* expr;
8510 	
8511 	      assert(conss != NULL && conss[c] != NULL);
8512 	      consdata = SCIPconsGetData(conss[c]);
8513 	      assert(consdata != NULL);
8514 	
8515 	      /* iterate through all expressions */
8516 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8517 	      {
8518 	         SCIP_EXPR** children = SCIPexprGetChildren(expr);
8519 	         SCIP_VAR* x = NULL;
8520 	         SCIP_VAR* y = NULL;
8521 	
8522 	         /* check whether the expression is of the form f(..)^2 */
8523 	         if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8524 	         {
8525 	            x = SCIPgetExprAuxVarNonlinear(children[0]);
8526 	            y = x;
8527 	         }
8528 	         /* check whether the expression is of the form f(..) * g(..) */
8529 	         else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8530 	         {
8531 	            x = SCIPgetExprAuxVarNonlinear(children[0]);
8532 	            y = SCIPgetExprAuxVarNonlinear(children[1]);
8533 	         }
8534 	
8535 	         /* add variables to the hash table */
8536 	         if( x != NULL && y != NULL )
8537 	         {
8538 	            SCIP_CALL( SCIPinsertBilinearTermExistingNonlinear(scip, conshdlr, x, y, SCIPgetExprAuxVarNonlinear(expr),
8539 	               SCIPgetExprNLocksPosNonlinear(expr), SCIPgetExprNLocksNegNonlinear(expr)) );
8540 	         }
8541 	      }
8542 	   }
8543 	
8544 	   /* release iterator */
8545 	   SCIPfreeExpriter(&it);
8546 	
8547 	   return SCIP_OKAY;
8548 	}
8549 	
8550 	/** store x, y and the locks in a new bilinear term */
8551 	static
8552 	SCIP_RETCODE bilinearTermsInsertEntry(
8553 	   SCIP*                 scip,               /**< SCIP data structure */
8554 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
8555 	   SCIP_VAR*             x,                  /**< the first variable */
8556 	   SCIP_VAR*             y,                  /**< the second variable */
8557 	   int                   nlockspos,          /**< number of positive locks of the bilinear term */
8558 	   int                   nlocksneg,          /**< number of negative locks of the bilinear term */
8559 	   int*                  idx,                /**< pointer to store the position of the term in bilinterms array */
8560 	   SCIP_Bool             existing            /**< whether the term exists explicitly in the problem */
8561 	   )
8562 	{
8563 	   SCIP_CONSHDLRDATA* conshdlrdata;
8564 	   SCIP_CONSNONLINEAR_BILINTERM* term;
8565 	
8566 	   assert(conshdlr != NULL);
8567 	   assert(x != NULL);
8568 	   assert(y != NULL);
8569 	   assert(nlockspos >= 0);
8570 	   assert(nlocksneg >= 0);
8571 	
8572 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8573 	   assert(conshdlrdata != NULL);
8574 	
8575 	   /* ensure that x.index <= y.index */
8576 	   if( SCIPvarCompare(x, y) == 1 )
8577 	   {
8578 	      SCIPswapPointers((void**)&x, (void**)&y);
8579 	   }
8580 	   assert(SCIPvarCompare(x, y) < 1);
8581 	
8582 	   *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8583 	
8584 	   /* update or create the term */
8585 	   if( *idx >= 0 )
8586 	   { /* the term has already been added */
8587 	      assert(conshdlrdata->bilinterms[*idx].x == x);
8588 	      assert(conshdlrdata->bilinterms[*idx].y == y);
8589 	
8590 	      /* get term and add locks */
8591 	      term = &conshdlrdata->bilinterms[*idx];
8592 	      assert(existing <= term->existing); /* implicit terms are added after existing ones */
8593 	      term->nlockspos += nlockspos;
8594 	      term->nlocksneg += nlocksneg;
8595 	   }
8596 	   else
8597 	   { /* this is the first time we encounter this product */
8598 	      /* ensure size of bilinterms array */
8599 	      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8600 	
8601 	      *idx = conshdlrdata->nbilinterms;
8602 	
8603 	      /* get term and set values in the created bilinear term */
8604 	      term = &conshdlrdata->bilinterms[*idx];
8605 	      assert(term != NULL);
8606 	      term->x = x;
8607 	      term->y = y;
8608 	      term->nauxexprs = 0;
8609 	      term->auxexprssize = 0;
8610 	      term->nlockspos = nlockspos;
8611 	      term->nlocksneg = nlocksneg;
8612 	      term->existing = existing;
8613 	      if( existing )
8614 	         term->aux.var = NULL;
8615 	      else
8616 	         term->aux.exprs = NULL;
8617 	
8618 	      /* increase the total number of bilinear terms */
8619 	      ++(conshdlrdata->nbilinterms);
8620 	
8621 	      /* save to the hashtable */
8622 	      if( conshdlrdata->bilinhashtable == NULL )
8623 	      {
8624 	         SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8625 	               bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8626 	               (void*)conshdlrdata) );
8627 	      }
8628 	      assert(conshdlrdata->bilinhashtable != NULL);
8629 	
8630 	      /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8631 	       * because zero can not be inserted into hash table
8632 	       */
8633 	      SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8634 	
8635 	      /* capture product variables */
8636 	      SCIP_CALL( SCIPcaptureVar(scip, x) );
8637 	      SCIP_CALL( SCIPcaptureVar(scip, y) );
8638 	   }
8639 	
8640 	   return SCIP_OKAY;
8641 	}
8642 	
8643 	/** frees array of bilinear terms and hash table */
8644 	static
8645 	SCIP_RETCODE bilinearTermsFree(
8646 	   SCIP*                 scip,               /**< SCIP data structure */
8647 	   SCIP_CONSHDLRDATA*    conshdlrdata        /**< constraint handler data */
8648 	   )
8649 	{
8650 	   int i;
8651 	   int j;
8652 	
8653 	   assert(conshdlrdata != NULL);
8654 	
8655 	   /* check whether bilinear terms have been stored */
8656 	   if( conshdlrdata->bilinterms == NULL )
8657 	   {
8658 	      assert(conshdlrdata->bilinterms == NULL);
8659 	      assert(conshdlrdata->nbilinterms == 0);
8660 	      assert(conshdlrdata->bilintermssize == 0);
8661 	
8662 	      return SCIP_OKAY;
8663 	   }
8664 	
8665 	   /* release variables */
8666 	   for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8667 	   {
8668 	      SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8669 	      SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8670 	
8671 	      for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8672 	      {
8673 	         if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8674 	         {
8675 	            SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8676 	         }
8677 	         SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8678 	      }
8679 	
8680 	      if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8681 	      {
8682 	         SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8683 	         continue;
8684 	      }
8685 	
8686 	      /* the rest is for simple terms with a single auxvar */
8687 	
8688 	      /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8689 	      if( conshdlrdata->bilinterms[i].aux.var != NULL )
8690 	      {
8691 	         SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8692 	      }
8693 	   }
8694 	
8695 	   /* free hash table */
8696 	   if( conshdlrdata->bilinhashtable != NULL )
8697 	   {
8698 	      SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8699 	   }
8700 	
8701 	   /* free bilinterms array; reset counters */
8702 	   SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8703 	   conshdlrdata->nbilinterms = 0;
8704 	   conshdlrdata->bilintermssize = 0;
8705 	
8706 	   return SCIP_OKAY;
8707 	}
8708 	
8709 	/*
8710 	 * vertex polyhedral separation
8711 	 */
8712 	
8713 	/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8714 	static
8715 	SCIP_RETCODE buildVertexPolyhedralSeparationLP(
8716 	   SCIP*                 scip,               /**< SCIP data structure */
8717 	   int                   nvars,              /**< number of (unfixed) variables in vertex-polyhedral functions */
8718 	   SCIP_LPI**            lp                  /**< pointer to store created LP */
8719 	   )
8720 	{
8721 	   SCIP_Real* obj;
8722 	   SCIP_Real* lb;
8723 	   SCIP_Real* ub;
8724 	   SCIP_Real* val;
8725 	   int* beg;
8726 	   int* ind;
8727 	   unsigned int nnonz;
8728 	   unsigned int ncols;
8729 	   unsigned int nrows;
8730 	   unsigned int i;
8731 	   unsigned int k;
8732 	
8733 	   assert(scip != NULL);
8734 	   assert(lp != NULL);
8735 	   assert(nvars > 0);
8736 	   assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8737 	
8738 	   SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8739 	
8740 	   /* create lpi to store the LP */
8741 	   SCIP_CALL( SCIPlpiCreate(lp, SCIPgetMessagehdlr(scip), "facet finding LP", SCIP_OBJSEN_MINIMIZE) );
8742 	
8743 	   nrows = (unsigned int)nvars + 1;
8744 	   ncols = POWEROFTWO((unsigned int)nvars);
8745 	   nnonz = (ncols * (nrows + 1)) / 2;
8746 	
8747 	   /* allocate necessary memory; set obj, lb, and ub to zero */
8748 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
8749 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &lb, ncols) );
8750 	   SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8751 	   SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8752 	   SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8753 	   SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8754 	
8755 	   /* calculate nonzero entries in the LP */
8756 	   for( i = 0, k = 0; i < ncols; ++i )
8757 	   {
8758 	      int row;
8759 	      unsigned int a;
8760 	
8761 	      /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8762 	      ub[i] = SCIPlpiInfinity(*lp);
8763 	
8764 	      SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8765 	      beg[i] = (int)k;
8766 	      row = 0;
8767 	
8768 	      /* iterate through the bit representation of i */
8769 	      a = 1;
8770 	      while( a <= i )
8771 	      {
8772 	         if( (a & i) != 0 )
8773 	         {
8774 	            val[k] = 1.0;
8775 	            ind[k] = row;
8776 	
8777 	            SCIPdebugMsg(scip, " val[%d][%u] = 1 (position  %u)\n", row, i, k);
8778 	
8779 	            ++k;
8780 	         }
8781 	
8782 	         a <<= 1;
8783 	         ++row;
8784 	         assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8785 	         assert(POWEROFTWO(row) == a);
8786 	      }
8787 	
8788 	      /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8789 	      val[k] = 1.0;
8790 	      ind[k] = (int)nrows - 1;
8791 	      ++k;
8792 	      SCIPdebugMsg(scip, " val[%u][%u] = 1 (position  %u)\n", nrows - 1, i, k);
8793 	   }
8794 	   assert(k == nnonz);
8795 	
8796 	   /* load all data into LP interface
8797 	    * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8798 	    */
8799 	   assert(nrows <= ncols);
8800 	   SCIP_CALL( SCIPlpiLoadColLP(*lp, SCIP_OBJSEN_MINIMIZE,
8801 	      (int)ncols, obj, lb, ub, NULL,
8802 	      (int)nrows, lb, lb, NULL,
8803 	      (int)nnonz, beg, ind, val) );
8804 	
8805 	   /* for the last row, we can set the rhs to 1.0 already */
8806 	   ind[0] = (int)nrows - 1;
8807 	   val[0] = 1.0;
8808 	   SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8809 	
8810 	   /* free allocated memory */
8811 	   SCIPfreeBufferArray(scip, &ind);
8812 	   SCIPfreeBufferArray(scip, &val);
8813 	   SCIPfreeBufferArray(scip, &beg);
8814 	   SCIPfreeBufferArray(scip, &ub);
8815 	   SCIPfreeBufferArray(scip, &lb);
8816 	   SCIPfreeBufferArray(scip, &obj);
8817 	
8818 	   return SCIP_OKAY;
8819 	}
8820 	
8821 	/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8822 	 * \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
8823 	 * set of vertices of the domain
8824 	 */
8825 	static
8826 	SCIP_Real computeVertexPolyhedralMaxFacetError(
8827 	   SCIP*                 scip,               /**< SCIP data structure */
8828 	   SCIP_Bool             overestimate,       /**< whether we check for an over or underestimator */
8829 	   SCIP_Real*            funvals,            /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8830 	   SCIP_Real*            box,                /**< box for which facet was computed, length: 2*nallvars */
8831 	   int                   nallvars,           /**< number of all variables */
8832 	   int                   nvars,              /**< number of unfixed variables */
8833 	   int*                  nonfixedpos,        /**< indices of unfixed variables, length: nvars */
8834 	   SCIP_Real*            facetcoefs,         /**< current facet candidate's coefficients, length: nallvars */
8835 	   SCIP_Real             facetconstant       /**< current facet candidate's constant, length: nallvars */
8836 	   )
8837 	{
8838 	   SCIP_Real maxerror;
8839 	   SCIP_Real facetval;
8840 	   SCIP_Real funval;
8841 	   SCIP_Real error;
8842 	   unsigned int i;
8843 	   unsigned int ncorners;
8844 	   unsigned int prev;
8845 	
8846 	   assert(scip != NULL);
8847 	   assert(funvals != NULL);
8848 	   assert(box != NULL);
8849 	   assert(nonfixedpos != NULL);
8850 	   assert(facetcoefs != NULL);
8851 	
8852 	   ncorners = POWEROFTWO(nvars);
8853 	   maxerror = 0.0;
8854 	
8855 	   /* check the origin (all variables at lower bound) */
8856 	   facetval = facetconstant;
8857 	   for( i = 0; i < (unsigned int) nallvars; ++i )
8858 	      facetval += facetcoefs[i] * box[2*i];
8859 	
8860 	   /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8861 	   funval = funvals[0];
8862 	   if( overestimate )
8863 	      error = funval - facetval;
8864 	   else
8865 	      error = facetval - funval;
8866 	
8867 	   /* update maximum error */
8868 	   maxerror = MAX(error, maxerror);
8869 	
8870 	   prev = 0;
8871 	   for( i = 1; i < ncorners; ++i )
8872 	   {
8873 	      unsigned int gray;
8874 	      unsigned int diff;
8875 	      unsigned int pos;
8876 	      int origpos;
8877 	
8878 	      gray = i ^ (i >> 1);
8879 	      diff = gray ^ prev;
8880 	
8881 	      /* compute position of unique 1 of diff */
8882 	      pos = 0;
8883 	      while( (diff >>= 1) != 0 )
8884 	         ++pos;
8885 	      assert(pos < (unsigned int)nvars);
8886 	
8887 	      origpos = nonfixedpos[pos];
8888 	
8889 	      if( gray > prev )
8890 	         facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8891 	      else
8892 	         facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8893 	
8894 	      /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8895 	      funval = funvals[gray];
8896 	      if( overestimate )
8897 	         error = funval - facetval;
8898 	      else
8899 	         error = facetval - funval;
8900 	
8901 	      /* update  maximum error */
8902 	      maxerror = MAX(error, maxerror);
8903 	
8904 	      prev = gray;
8905 	   }
8906 	
8907 	   SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8908 	
8909 	   return maxerror;
8910 	}
8911 	
8912 	/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */  /*lint -e{715}*/
8913 	static
8914 	SCIP_RETCODE computeVertexPolyhedralFacetLP(
8915 	   SCIP*                 scip,               /**< SCIP data structure */
8916 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
8917 	   SCIP_Bool             overestimate,       /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8918 	   SCIP_Real*            xstar,              /**< point to be separated */
8919 	   SCIP_Real*            box,                /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8920 	   int                   nallvars,           /**< half of the length of box */
8921 	   int*                  nonfixedpos,        /**< indices of nonfixed variables */
8922 	   SCIP_Real*            funvals,            /**< values of function in all corner points (w.r.t. nonfixed variables) */
8923 	   int                   nvars,              /**< number of nonfixed variables */
8924 	   SCIP_Real             targetvalue,        /**< target value: no need to compute facet if value in xstar would be worse than this value */
8925 	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
8926 	   SCIP_Real*            facetcoefs,         /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8927 	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
8928 	   )
8929 	{  /*lint --e{715}*/
8930 	   SCIP_CONSHDLRDATA* conshdlrdata;
8931 	   SCIP_LPI* lp;
8932 	   SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8933 	   int* inds;
8934 	   int ncols;
8935 	   int nrows;
8936 	   int i;
8937 	   SCIP_Real facetvalue;
8938 	   SCIP_Real mindomwidth;
8939 	   SCIP_RETCODE lpsolveretcode;
8940 	
8941 	   assert(scip != NULL);
8942 	   assert(conshdlr != NULL);
8943 	   assert(xstar != NULL);
8944 	   assert(box != NULL);
8945 	   assert(nonfixedpos != NULL);
8946 	   assert(funvals != NULL);
8947 	   assert(nvars >= 0);
8948 	   assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8949 	   assert(success != NULL);
8950 	   assert(facetcoefs != NULL);
8951 	   assert(facetconstant != NULL);
8952 	
8953 	   *success = FALSE;
8954 	
8955 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8956 	   assert(conshdlrdata != NULL);
8957 	
8958 	   if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8959 	   {
8960 	      SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8961 	   }
8962 	
8963 	   /* construct an LP for this size, if not having one already */
8964 	   if( conshdlrdata->vp_lp[nvars] == NULL )
8965 	   {
8966 	      SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8967 	   }
8968 	   lp = conshdlrdata->vp_lp[nvars];
8969 	   assert(lp != NULL);
8970 	
8971 	   /* get number of cols and rows of separation lp */
8972 	   SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8973 	   SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8974 	
8975 	   /* number of columns should equal the number of corners = 2^nvars */
8976 	   assert(ncols == (int)POWEROFTWO(nvars));
8977 	
8978 	   /* allocate necessary memory */
8979 	   SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8980 	   SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8981 	
8982 	   /*
8983 	    * set up the described LP on the transformed space
8984 	    */
8985 	
8986 	   for( i = 0; i < ncols; ++i )
8987 	      inds[i] = i;
8988 	
8989 	   /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
8990 	   mindomwidth = 2*SCIPinfinity(scip);
8991 	   for( i = 0; i < nrows-1; ++i )
8992 	   {
8993 	      SCIP_Real solval;
8994 	      SCIP_Real lb;
8995 	      SCIP_Real ub;
8996 	      int varpos;
8997 	
8998 	      assert(i < nvars);
8999 	
9000 	      varpos = nonfixedpos[i];
9001 	      lb = box[2 * varpos];
9002 	      ub = box[2 * varpos + 1];
9003 	      solval = xstar[varpos];
9004 	
9005 	      if( ub - lb < mindomwidth )
9006 	         mindomwidth = ub - lb;
9007 	
9008 	      /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9009 	      if( solval <= lb )
9010 	         aux[i] = 0.0;
9011 	      else if( solval >= ub )
9012 	         aux[i] = 1.0;
9013 	      else
9014 	         aux[i] = (solval - lb) / (ub - lb);
9015 	
9016 	      /* perturb point to hopefully obtain a facet of the convex envelope */
9017 	      if( conshdlrdata->vp_maxperturb > 0.0 )
9018 	      {
9019 	         assert(conshdlrdata->vp_randnumgen != NULL);
9020 	
9021 	         if( aux[i] == 1.0 )
9022 	            aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9023 	         else if( aux[i] == 0.0 )
9024 	            aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9025 	         else
9026 	         {
9027 	            SCIP_Real perturbation;
9028 	
9029 	            perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9030 	            perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9031 	            aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9032 	         }
9033 	         assert(0.0 < aux[i] && aux[i] < 1.0);
9034 	      }
9035 	
9036 	      SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9037 	   }
9038 	
9039 	   /* update LP */
9040 	   SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9041 	   SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9042 	   SCIP_CALL( SCIPlpiChgObjsen(lp, overestimate ? SCIP_OBJSEN_MAXIMIZE : SCIP_OBJSEN_MINIMIZE) );
9043 	
9044 	   /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9045 	   if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9046 	   {
9047 	      SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9048 	   }
9049 	   /* set an iteration limit so we do not run forever */
9050 	   SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPITLIM, 100*ncols) );
9051 	   /* 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 */
9052 	   SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_FEASTOL, SCIPfeastol(scip)) );
9053 	   /* since we work with the dual of the LP, dual feastol determines validity of the facet
9054 	    * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9055 	    * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9056 	    */
9057 	   SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, MIN(SCIPfeastol(scip), MAX(SCIPepsilon(scip), mindomwidth * SCIPfeastol(scip)))) );
9058 	
9059 	#ifdef SCIP_DEBUG
9060 	   SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPINFO, 1) );
9061 	#endif
9062 	
9063 	   /*
9064 	    * solve the LP and store the resulting facet for the transformed space
9065 	    */
9066 	   if( conshdlrdata->vp_dualsimplex )
9067 	   {
9068 	      lpsolveretcode = SCIPlpiSolveDual(lp);
9069 	   }
9070 	   else
9071 	   {
9072 	      lpsolveretcode = SCIPlpiSolvePrimal(lp);
9073 	   }
9074 	   if( lpsolveretcode == SCIP_LPERROR )
9075 	   {
9076 	      SCIPdebugMsg(scip, "LP error, aborting.\n");
9077 	      goto CLEANUP;
9078 	   }
9079 	   SCIP_CALL( lpsolveretcode );
9080 	
9081 	   /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9082 	   if( !SCIPlpiIsDualFeasible(lp) )
9083 	   {
9084 	      SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9085 	      goto CLEANUP;
9086 	   }
9087 	
9088 	   /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9089 	    * columns than needed, in particular, \bar \beta is the last dual multiplier
9090 	    */
9091 	   SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9092 	
9093 	   for( i = 0; i < nvars; ++i )
9094 	      facetcoefs[nonfixedpos[i]] = aux[i];
9095 	   /* last dual multiplier is the constant */
9096 	   *facetconstant = aux[nrows - 1];
9097 	
9098 	#ifdef SCIP_DEBUG
9099 	   SCIPdebugMsg(scip, "facet for the transformed problem: ");
9100 	   for( i = 0; i < nallvars; ++i )
9101 	   {
9102 	      SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9103 	   }
9104 	   SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9105 	#endif
9106 	
9107 	   /*
9108 	    * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9109 	    */
9110 	
9111 	   SCIPdebugMsg(scip, "facet in orig. space: ");
9112 	
9113 	   facetvalue = 0.0;
9114 	   for( i = 0; i < nvars; ++i )
9115 	   {
9116 	      SCIP_Real lb;
9117 	      SCIP_Real ub;
9118 	      int varpos;
9119 	
9120 	      varpos = nonfixedpos[i];
9121 	      lb = box[2 * varpos];
9122 	      ub = box[2 * varpos + 1];
9123 	      assert(!SCIPisEQ(scip, lb, ub));
9124 	
9125 	      /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9126 	      facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9127 	
9128 	      /* beta = beta_bar - sum_i alpha_i * lb_i */
9129 	      *facetconstant -= facetcoefs[varpos] * lb;
9130 	
9131 	      /* evaluate */
9132 	      facetvalue += facetcoefs[varpos] * xstar[varpos];
9133 	
9134 	      SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9135 	   }
9136 	   SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9137 	
9138 	   /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9139 	   facetvalue += *facetconstant;
9140 	
9141 	   SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9142 	
9143 	    /* if overestimate, then we want facetvalue < targetvalue
9144 	    * if underestimate, then we want facetvalue > targetvalue
9145 	    * if none holds, give up
9146 	    * so maybe here we should check against the minimal violation
9147 	    */
9148 	   if( overestimate == (facetvalue > targetvalue) )
9149 	   {
9150 	      SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9151 	      goto CLEANUP;
9152 	   }
9153 	
9154 	   /* if we made it until here, then we have a nice facet */
9155 	   *success = TRUE;
9156 	
9157 	CLEANUP:
9158 	   /* free allocated memory */
9159 	   SCIPfreeBufferArray(scip, &inds);
9160 	   SCIPfreeBufferArray(scip, &aux);
9161 	
9162 	   return SCIP_OKAY;
9163 	}
9164 	
9165 	/** computes a facet of the convex or concave envelope of a univariant vertex polyhedral function
9166 	 *
9167 	 * In other words, compute the line that passes through two given points.
9168 	 */
9169 	static
9170 	SCIP_RETCODE computeVertexPolyhedralFacetUnivariate(
9171 	   SCIP*                 scip,               /**< SCIP data structure */
9172 	   SCIP_Real             left,               /**< left coordinate */
9173 	   SCIP_Real             right,              /**< right coordinate */
9174 	   SCIP_Real             funleft,            /**< value of function in left coordinate */
9175 	   SCIP_Real             funright,           /**< value of function in right coordinate */
9176 	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
9177 	   SCIP_Real*            facetcoef,          /**< buffer to store coefficient of facet defining inequality */
9178 	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
9179 	   )
9180 	{
9181 	   assert(scip != NULL);
9182 	   assert(SCIPisLE(scip, left, right));
9183 	   assert(!SCIPisInfinity(scip, -left));
9184 	   assert(!SCIPisInfinity(scip, right));
9185 	   assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9186 	   assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9187 	   assert(success != NULL);
9188 	   assert(facetcoef != NULL);
9189 	   assert(facetconstant != NULL);
9190 	
9191 	   *facetcoef = (funright - funleft) / (right - left);
9192 	   *facetconstant = funleft - *facetcoef * left;
9193 	
9194 	   *success = TRUE;
9195 	
9196 	   return SCIP_OKAY;
9197 	}
9198 	
9199 	/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9200 	 *
9201 	 * Three points a, b, and c are given.
9202 	 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9203 	 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9204 	 */
9205 	static
9206 	SCIP_RETCODE computeHyperplaneThreePoints(
9207 	   SCIP*                 scip,               /**< SCIP data structure */
9208 	   SCIP_Real             a1,                 /**< first coordinate of a */
9209 	   SCIP_Real             a2,                 /**< second coordinate of a */
9210 	   SCIP_Real             a3,                 /**< third coordinate of a */
9211 	   SCIP_Real             b1,                 /**< first coordinate of b */
9212 	   SCIP_Real             b2,                 /**< second coordinate of b */
9213 	   SCIP_Real             b3,                 /**< third coordinate of b */
9214 	   SCIP_Real             c1,                 /**< first coordinate of c */
9215 	   SCIP_Real             c2,                 /**< second coordinate of c */
9216 	   SCIP_Real             c3,                 /**< third coordinate of c */
9217 	   SCIP_Real*            alpha,              /**< coefficient of first coordinate */
9218 	   SCIP_Real*            beta,               /**< coefficient of second coordinate */
9219 	   SCIP_Real*            gamma_,             /**< coefficient of third coordinate */
9220 	   SCIP_Real*            delta               /**< constant right-hand side */
9221 	   )
9222 	{
9223 	   assert(scip != NULL);
9224 	   assert(alpha != NULL);
9225 	   assert(beta  != NULL);
9226 	   assert(gamma_ != NULL);
9227 	   assert(delta != NULL);
9228 	
9229 	   *alpha  = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9230 	   *beta   = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9231 	   *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9232 	   *delta  = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9233 	
9234 	   /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9235 	
9236 	   if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9237 	      SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9238 	      SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9239 	   {
9240 	      SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9241 	      *delta  = 0.0;
9242 	      *alpha  = 0.0;
9243 	      *beta   = 0.0;
9244 	      *gamma_ = 0.0;
9245 	      return SCIP_OKAY;
9246 	   }
9247 	
9248 	   /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9249 	   if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9250 	      !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9251 	      !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9252 	   {
9253 	      SCIP_Real m[9];
9254 	      SCIP_Real rhs[3];
9255 	      SCIP_Real x[3];
9256 	      SCIP_Bool success;
9257 	
9258 	      /*
9259 	      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));
9260 	      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));
9261 	      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));
9262 	      */
9263 	
9264 	      /* initialize matrix column-wise */
9265 	      m[0] = a1;
9266 	      m[1] = b1;
9267 	      m[2] = c1;
9268 	      m[3] = a2;
9269 	      m[4] = b2;
9270 	      m[5] = c2;
9271 	      m[6] = a3;
9272 	      m[7] = b3;
9273 	      m[8] = c3;
9274 	
9275 	      rhs[0] = 1.0;
9276 	      rhs[1] = 1.0;
9277 	      rhs[2] = 1.0;
9278 	
9279 	      SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9280 	
9281 	      /* solve the linear problem */
9282 	      SCIP_CALL( SCIPsolveLinearEquationsIpopt(3, m, rhs, x, &success) );
9283 	
9284 	      *delta  = rhs[0];
9285 	      *alpha  = x[0];
9286 	      *beta   = x[1];
9287 	      *gamma_ = x[2];
9288 	
9289 	      /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9290 	       * not add a cut to SCIP and that all assertions are trivially fulfilled
9291 	       */
9292 	      if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9293 	         !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9294 	         !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9295 	      {
9296 	         SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9297 	         *delta  = 0.0;
9298 	         *alpha  = 0.0;
9299 	         *beta   = 0.0;
9300 	         *gamma_ = 0.0;
9301 	      }
9302 	   }
9303 	
9304 	   if( *gamma_ < 0.0 )
9305 	   {
9306 	      *alpha  = -*alpha;
9307 	      *beta   = -*beta;
9308 	      *gamma_ = -*gamma_;
9309 	      *delta  = -*delta;
9310 	   }
9311 	
9312 	   return SCIP_OKAY;
9313 	}
9314 	
9315 	/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9316 	static
9317 	SCIP_RETCODE computeVertexPolyhedralFacetBivariate(
9318 	   SCIP*                 scip,               /**< SCIP data structure */
9319 	   SCIP_Bool             overestimate,       /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9320 	   SCIP_Real             p1[2],              /**< first vertex of box */
9321 	   SCIP_Real             p2[2],              /**< second vertex of box */
9322 	   SCIP_Real             p3[2],              /**< third vertex of box */
9323 	   SCIP_Real             p4[2],              /**< forth vertex of box */
9324 	   SCIP_Real             p1val,              /**< value in p1 */
9325 	   SCIP_Real             p2val,              /**< value in p2 */
9326 	   SCIP_Real             p3val,              /**< value in p3 */
9327 	   SCIP_Real             p4val,              /**< value in p4 */
9328 	   SCIP_Real             xstar[2],           /**< point to be separated */
9329 	   SCIP_Real             targetvalue,        /**< target value: no need to compute facet if value in xstar would be worse than this value */
9330 	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
9331 	   SCIP_Real*            facetcoefs,         /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9332 	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
9333 	   )
9334 	{
9335 	   SCIP_Real alpha, beta, gamma_, delta;
9336 	   SCIP_Real xstarval, candxstarval = 0.0;
9337 	   int leaveout;
9338 	
9339 	   assert(scip != NULL);
9340 	   assert(success != NULL);
9341 	   assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9342 	   assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9343 	   assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9344 	   assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9345 	   assert(facetcoefs != NULL);
9346 	   assert(facetconstant != NULL);
9347 	
9348 	   *success = FALSE;
9349 	
9350 	   /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9351 	   if( !overestimate )
9352 	   {
9353 	      p1val = -p1val;
9354 	      p2val = -p2val;
9355 	      p3val = -p3val;
9356 	      p4val = -p4val;
9357 	      targetvalue = -targetvalue;
9358 	   }
9359 	
9360 	   SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9361 	   SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9362 	   SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9363 	   SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9364 	
9365 	   /* Compute coefficients alpha, beta, gamma (>0), delta such that
9366 	    *   alpha*x + beta*y + gamma*z = delta
9367 	    * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9368 	    * the fourth corner point lies below this hyperplane.
9369 	    * 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.,
9370 	    *    alpha*x + beta*y - delta <= -gamma * f(x,y),
9371 	    * or, equivalently,
9372 	    *   -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9373 	    */
9374 	   for( leaveout = 1; leaveout <= 4; ++leaveout )
9375 	   {
9376 	      switch( leaveout)
9377 	      {
9378 	         case 1 :
9379 	            /* get hyperplane through p2, p3, p4 */
9380 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9381 	               &alpha, &beta, &gamma_, &delta) );
9382 	            /* if not underestimating in p1, then go to next candidate */
9383 	            if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9384 	               continue;
9385 	            break;
9386 	
9387 	         case 2 :
9388 	            /* get hyperplane through p1, p3, p4 */
9389 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9390 	               &alpha, &beta, &gamma_, &delta) );
9391 	            /* if not underestimating in p2, then go to next candidate */
9392 	            if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9393 	               continue;
9394 	            break;
9395 	
9396 	         case 3 :
9397 	            /* get hyperplane through p1, p2, p4 */
9398 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9399 	               &alpha, &beta, &gamma_, &delta) );
9400 	            /* if not underestimating in p3, then go to next candidate */
9401 	            if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9402 	               continue;
9403 	            break;
9404 	
9405 	         case 4 :
9406 	            /* get hyperplane through p1, p2, p3 */
9407 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9408 	               &alpha, &beta, &gamma_, &delta) );
9409 	            /* if not underestimating in p4, then stop */
9410 	            if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9411 	               continue;
9412 	            break;
9413 	
9414 	         default: /* only for lint */
9415 	            alpha = SCIP_INVALID;
9416 	            beta = SCIP_INVALID;
9417 	            gamma_ =  SCIP_INVALID;
9418 	            delta = SCIP_INVALID;
9419 	            break;
9420 	      }
9421 	
9422 	      /* check if bad luck: should not happen if numerics are fine */
9423 	      if( SCIPisZero(scip, gamma_) )
9424 	         continue;
9425 	      assert(!SCIPisNegative(scip, gamma_));
9426 	
9427 	      /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9428 	      if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9429 	         ( !SCIPisZero(scip, beta)  && SCIPisZero(scip, beta/gamma_)) )
9430 	         continue;
9431 	
9432 	      SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9433 	
9434 	      /* value of hyperplane candidate in xstar */
9435 	      xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9436 	
9437 	      /* if reaching target and first or better than previous candidate, then update */
9438 	      if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9439 	      {
9440 	         /* flip hyperplane */
9441 	         if( !overestimate )
9442 	            gamma_ = -gamma_;
9443 	
9444 	         facetcoefs[0] = -alpha/gamma_;
9445 	         facetcoefs[1] = -beta/gamma_;
9446 	         *facetconstant = delta/gamma_;
9447 	
9448 	         *success = TRUE;
9449 	         candxstarval = xstarval;
9450 	      }
9451 	   }
9452 	
9453 	   return SCIP_OKAY;
9454 	}
9455 	
9456 	/*
9457 	 * Callback methods of constraint handler
9458 	 */
9459 	
9460 	/** copy method for constraint handler plugins (called when SCIP copies plugins) */
9461 	static
9462 	SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
9463 	{  /*lint --e{715}*/
9464 	   SCIP_CONSHDLR*     targetconshdlr;
9465 	   SCIP_CONSHDLRDATA* sourceconshdlrdata;
9466 	   int                i;
9467 	
9468 	   assert(scip != NULL);
9469 	   assert(conshdlr != NULL);
9470 	   assert(valid != NULL);
9471 	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
9472 	
9473 	   /* create basic data of constraint handler and include it to scip */
9474 	   SCIP_CALL( SCIPincludeConshdlrNonlinear(scip) );
9475 	
9476 	   targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9477 	   assert(targetconshdlr != NULL);
9478 	   assert(targetconshdlr != conshdlr);
9479 	
9480 	   sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
9481 	   assert(sourceconshdlrdata != NULL);
9482 	
9483 	   /* copy nonlinear handlers */
9484 	   for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
9485 	   {
9486 	      SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
9487 	   }
9488 	
9489 	   *valid = TRUE;
9490 	
9491 	   return SCIP_OKAY;
9492 	}
9493 	
9494 	/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9495 	static
9496 	SCIP_DECL_CONSFREE(consFreeNonlinear)
9497 	{  /*lint --e{715}*/
9498 	   SCIP_CONSHDLRDATA* conshdlrdata;
9499 	   int i;
9500 	
9501 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9502 	   assert(conshdlrdata != NULL);
9503 	
9504 	   /* free nonlinear handlers */
9505 	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9506 	   {
9507 	      SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
9508 	      assert(conshdlrdata->nlhdlrs[i] == NULL);
9509 	   }
9510 	   SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
9511 	   conshdlrdata->nlhdlrssize = 0;
9512 	
9513 	   /* free upgrade functions */
9514 	   for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
9515 	   {
9516 	      assert(conshdlrdata->consupgrades[i] != NULL);
9517 	      SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
9518 	   }
9519 	   SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
9520 	
9521 	   SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
9522 	
9523 	   SCIPqueueFree(&conshdlrdata->reversepropqueue);
9524 	
9525 	   if( conshdlrdata->vp_randnumgen != NULL )
9526 	      SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9527 	
9528 	   /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9529 	   for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9530 	   {
9531 	      if( conshdlrdata->vp_lp[i] != NULL )
9532 	      {
9533 	         SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9534 	      }
9535 	   }
9536 	
9537 	   assert(conshdlrdata->branchrandnumgen == NULL);
9538 	
9539 	   assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
9540 	   SCIPhashmapFree(&conshdlrdata->var2expr);
9541 	
9542 	   SCIPfreeMemory(scip, &conshdlrdata);
9543 	   SCIPconshdlrSetData(conshdlr, NULL);
9544 	
9545 	   return SCIP_OKAY;
9546 	}
9547 	
9548 	
9549 	/** initialization method of constraint handler (called after problem was transformed) */
9550 	static
9551 	SCIP_DECL_CONSINIT(consInitNonlinear)
9552 	{  /*lint --e{715}*/
9553 	   SCIP_CONSHDLRDATA* conshdlrdata;
9554 	   int i;
9555 	
9556 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9557 	   assert(conshdlrdata != NULL);
9558 	
9559 	   /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
9560 	   conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
9561 	   /* set to 1 so it is larger than initial value of lastenforound in exprs */
9562 	   conshdlrdata->enforound = 1;
9563 	   /* reset numbering for auxiliary variables */
9564 	   conshdlrdata->auxvarid = 0;
9565 	
9566 	   for( i = 0; i < nconss; ++i )
9567 	   {
9568 	      SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
9569 	      SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
9570 	   }
9571 	
9572 	   /* sort nonlinear handlers by detection priority, in decreasing order */
9573 	   if( conshdlrdata->nnlhdlrs > 1 )
9574 	      SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
9575 	
9576 	   /* get heuristics for later use */
9577 	   conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9578 	   conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9579 	
9580 	   /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
9581 	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9582 	   {
9583 	      SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
9584 	   }
9585 	
9586 	   /* reset statistics in constraint handler */
9587 	   conshdlrdata->nweaksepa = 0;
9588 	   conshdlrdata->ntightenlp = 0;
9589 	   conshdlrdata->ndesperatebranch = 0;
9590 	   conshdlrdata->ndesperatecutoff = 0;
9591 	   conshdlrdata->ndesperatetightenlp = 0;
9592 	   conshdlrdata->nforcelp = 0;
9593 	   SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
9594 	   conshdlrdata->ncanonicalizecalls = 0;
9595 	
9596 	#ifdef ENFOLOGFILE
9597 	   ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
9598 	#endif
9599 	
9600 	   return SCIP_OKAY;
9601 	}
9602 	
9603 	
9604 	/** deinitialization method of constraint handler (called before transformed problem is freed) */
9605 	static
9606 	SCIP_DECL_CONSEXIT(consExitNonlinear)
9607 	{  /*lint --e{715}*/
9608 	   SCIP_CONSHDLRDATA* conshdlrdata;
9609 	   SCIP_CONS** consssorted;
9610 	   int i;
9611 	
9612 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9613 	   assert(conshdlrdata != NULL);
9614 	
9615 	   if( nconss > 0 )
9616 	   {
9617 	      /* for better performance of dropVarEvents, we sort by index, descending */
9618 	      SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
9619 	      SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
9620 	
9621 	      for( i = 0; i < nconss; ++i )
9622 	      {
9623 	         SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
9624 	         SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
9625 	      }
9626 	
9627 	      SCIPfreeBufferArray(scip, &consssorted);
9628 	   }
9629 	
9630 	   conshdlrdata->subnlpheur = NULL;
9631 	   conshdlrdata->trysolheur = NULL;
9632 	
9633 	   if( conshdlrdata->vp_randnumgen != NULL )
9634 	      SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9635 	
9636 	   /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9637 	   for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9638 	   {
9639 	      if( conshdlrdata->vp_lp[i] != NULL )
9640 	      {
9641 	         SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9642 	      }
9643 	   }
9644 	
9645 	   if( conshdlrdata->branchrandnumgen != NULL )
9646 	      SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
9647 	
9648 	   /* deinitialize nonlinear handlers */
9649 	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9650 	   {
9651 	      SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
9652 	   }
9653 	
9654 	   ENFOLOG(
9655 	   if( enfologfile != NULL )
9656 	   {
9657 	      fclose(enfologfile);
9658 	      enfologfile = NULL;
9659 	   })
9660 	
9661 	   return SCIP_OKAY;
9662 	}
9663 	
9664 	
9665 	/** presolving initialization method of constraint handler (called when presolving is about to begin) */
9666 	#ifdef SCIP_DISABLED_CODE
9667 	static
9668 	SCIP_DECL_CONSINITPRE(consInitpreNonlinear)
9669 	{  /*lint --e{715}*/
9670 	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
9671 	   SCIPABORT(); /*lint --e{527}*/
9672 	
9673 	   return SCIP_OKAY;
9674 	}
9675 	#else
9676 	#define consInitpreNonlinear NULL
9677 	#endif
9678 	
9679 	
9680 	/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9681 	static
9682 	SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
9683 	{  /*lint --e{715}*/
9684 	   SCIP_Bool infeasible;
9685 	
9686 	   if( nconss == 0 )
9687 	      return SCIP_OKAY;
9688 	
9689 	   /* skip some extra work if already known to be infeasible */
9690 	   if( SCIPgetStatus(scip) == SCIP_STATUS_INFEASIBLE )
9691 	      return SCIP_OKAY;
9692 	
9693 	   /* simplify constraints and replace common subexpressions */
9694 	   SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
9695 	
9696 	   /* currently SCIP does not offer to communicate this,
9697 	    * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
9698 	    * or if a constraint expression became constant
9699 	    */
9700 	   assert(!infeasible);
9701 	
9702 	   /* tell SCIP that we have something nonlinear */
9703 	   SCIPenableNLP(scip);
9704 	
9705 	   return SCIP_OKAY;
9706 	}
9707 	
9708 	
9709 	/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
9710 	static
9711 	SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
9712 	{  /*lint --e{715}*/
9713 	   SCIP_CONSHDLRDATA* conshdlrdata;
9714 	   int i;
9715 	
9716 	   /* skip remaining initializations if we have solved already
9717 	    * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
9718 	    * assumes nonempty activities in expressions
9719 	    */
9720 	   switch( SCIPgetStatus(scip) )
9721 	   {
9722 	      case SCIP_STATUS_OPTIMAL:
9723 	      case SCIP_STATUS_INFEASIBLE:
9724 	      case SCIP_STATUS_UNBOUNDED:
9725 	      case SCIP_STATUS_INFORUNBD:
9726 	         return SCIP_OKAY;
9727 	      default: ;
9728 	   } /*lint !e788 */
9729 	
9730 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9731 	   assert(conshdlrdata != NULL);
9732 	
9733 	   /* reset one of the number of detections counter to count only current round */
9734 	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9735 	      SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
9736 	
9737 	   SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
9738 	
9739 	   /* catch new solution event */
9740 	   if( nconss != 0 && conshdlrdata->linearizeheursol != 'o' )
9741 	   {
9742 	      SCIP_EVENTHDLR* eventhdlr;
9743 	
9744 	      eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9745 	      assert(eventhdlr != NULL);
9746 	
9747 	      SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
9748 	         eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9749 	   }
9750 	
9751 	   /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
9752 	   if( conshdlrdata->branchpscostweight > 0.0 )
9753 	   {
9754 	      SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
9755 	      if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
9756 	      {
9757 	         SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
9758 	         SCIPABORT();
9759 	         return SCIP_INVALIDDATA;
9760 	      }
9761 	   }
9762 	
9763 	   return SCIP_OKAY;
9764 	}
9765 	
9766 	
9767 	/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9768 	static
9769 	SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
9770 	{  /*lint --e{715}*/
9771 	   SCIP_CONSHDLRDATA* conshdlrdata;
9772 	
9773 	   SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
9774 	
9775 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9776 	   assert(conshdlrdata != NULL);
9777 	
9778 	   /* free hash table for bilinear terms */
9779 	   SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
9780 	
9781 	   /* reset flag to allow another call of presolSingleLockedVars() after a restart */
9782 	   conshdlrdata->checkedvarlocks = FALSE;
9783 	
9784 	   /* drop catching new solution event, if catched before */
9785 	   if( conshdlrdata->newsoleventfilterpos >= 0 )
9786 	   {
9787 	      SCIP_EVENTHDLR* eventhdlr;
9788 	
9789 	      eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9790 	      assert(eventhdlr != NULL);
9791 	
9792 	      SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9793 	      conshdlrdata->newsoleventfilterpos = -1;
9794 	   }
9795 	
9796 	   return SCIP_OKAY;
9797 	}
9798 	
9799 	
9800 	/** frees specific constraint data */
9801 	static
9802 	SCIP_DECL_CONSDELETE(consDeleteNonlinear)
9803 	{  /*lint --e{715}*/
9804 	   assert(consdata != NULL);
9805 	   assert(*consdata != NULL);
9806 	   assert((*consdata)->expr != NULL);
9807 	
9808 	   /* constraint locks should have been removed */
9809 	   assert((*consdata)->nlockspos == 0);
9810 	   assert((*consdata)->nlocksneg == 0);
9811 	
9812 	   /* free variable expressions */
9813 	   SCIP_CALL( freeVarExprs(scip, *consdata) );
9814 	
9815 	   SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
9816 	
9817 	   /* free nonlinear row representation */
9818 	   if( (*consdata)->nlrow != NULL )
9819 	   {
9820 	      SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
9821 	   }
9822 	
9823 	   SCIPfreeBlockMemory(scip, consdata);
9824 	
9825 	   return SCIP_OKAY;
9826 	}
9827 	
9828 	
9829 	/** transforms constraint data into data belonging to the transformed problem */
9830 	static
9831 	SCIP_DECL_CONSTRANS(consTransNonlinear)
9832 	{  /*lint --e{715}*/
9833 	   SCIP_EXPR* targetexpr;
9834 	   SCIP_CONSDATA* sourcedata;
9835 	
9836 	   sourcedata = SCIPconsGetData(sourcecons);
9837 	   assert(sourcedata != NULL);
9838 	
9839 	   /* get a copy of sourceexpr with transformed vars */
9840 	   SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
9841 	   assert(targetexpr != NULL);  /* SCIPduplicateExpr cannot fail */
9842 	
9843 	   /* create transformed cons (only captures targetexpr, no need to copy again) */
9844 	   SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
9845 	      targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
9846 	      SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
9847 	      SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
9848 	      SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
9849 	      SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
9850 	
9851 	   /* release target expr */
9852 	   SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
9853 	
9854 	   return SCIP_OKAY;
9855 	}
9856 	
9857 	
9858 	/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9859 	static
9860 	SCIP_DECL_CONSINITLP(consInitlpNonlinear)
9861 	{  /*lint --e{715}*/
9862 	   /* create auxiliary variables and call separation initialization callbacks of the expression handlers
9863 	    * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
9864 	    *   during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
9865 	    *   for now, there is an assert in detectNlhdlrs to require initial if separated
9866 	    */
9867 	   SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
9868 	
9869 	   /* collect all bilinear terms for which an auxvar is present
9870 	    * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
9871 	    * addition (and removal?) of constraints during solve
9872 	    * this is typically the majority of constraints, but the method should be made more flexible
9873 	    */
9874 	   SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
9875 	
9876 	   return SCIP_OKAY;
9877 	}
9878 	
9879 	
9880 	/** separation method of constraint handler for LP solutions */
9881 	static
9882 	SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
9883 	{  /*lint --e{715}*/
9884 	   SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
9885 	
9886 	   return SCIP_OKAY;
9887 	}
9888 	
9889 	
9890 	/** separation method of constraint handler for arbitrary primal solutions */
9891 	static
9892 	SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
9893 	{  /*lint --e{715}*/
9894 	   SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
9895 	
9896 	   return SCIP_OKAY;
9897 	}
9898 	
9899 	
9900 	/** constraint enforcing method of constraint handler for LP solutions */
9901 	static
9902 	SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
9903 	{  /*lint --e{715}*/
9904 	   SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
9905 	
9906 	   return SCIP_OKAY;
9907 	}
9908 	
9909 	
9910 	/** constraint enforcing method of constraint handler for relaxation solutions */
9911 	static
9912 	SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
9913 	{  /*lint --e{715}*/
9914 	   SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
9915 	
9916 	   return SCIP_OKAY;
9917 	}
9918 	
9919 	
9920 	/** constraint enforcing method of constraint handler for pseudo solutions */
9921 	static
9922 	SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
9923 	{  /*lint --e{715}*/
9924 	   SCIP_RESULT propresult;
9925 	   SCIP_Longint soltag;
9926 	   int nchgbds;
9927 	   int nnotify;
9928 	   int c;
9929 	
9930 	   soltag = SCIPgetExprNewSoltag(scip);
9931 	
9932 	   *result = SCIP_FEASIBLE;
9933 	   for( c = 0; c < nconss; ++c )
9934 	   {
9935 	      SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
9936 	
9937 	      if( isConsViolated(scip, conss[c]) )
9938 	         *result = SCIP_INFEASIBLE;
9939 	   }
9940 	
9941 	   if( *result == SCIP_FEASIBLE )
9942 	      return SCIP_OKAY;
9943 	
9944 	   /* try to propagate
9945 	    * TODO obey propinenfo parameter, but we need something to recognize cutoff
9946 	    */
9947 	   nchgbds = 0;
9948 	   SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
9949 	
9950 	   if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
9951 	   {
9952 	      *result = propresult;
9953 	      return SCIP_OKAY;
9954 	   }
9955 	
9956 	   /* register all unfixed variables in all violated constraints as branching candidates */
9957 	   SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
9958 	   if( nnotify > 0 )
9959 	   {
9960 	      SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
9961 	
9962 	      return SCIP_OKAY;
9963 	   }
9964 	
9965 	   SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
9966 	   *result = SCIP_SOLVELP;
9967 	   ++SCIPconshdlrGetData(conshdlr)->nforcelp;
9968 	
9969 	   return SCIP_OKAY;
9970 	}
9971 	
9972 	
9973 	/** feasibility check method of constraint handler for integral solutions */
9974 	static
9975 	SCIP_DECL_CONSCHECK(consCheckNonlinear)
9976 	{  /*lint --e{715}*/
9977 	   SCIP_CONSHDLRDATA* conshdlrdata;
9978 	   SCIP_CONSDATA*     consdata;
9979 	   SCIP_Real          maxviol;
9980 	   SCIP_Bool          maypropfeasible;
9981 	   SCIP_Longint       soltag;
9982 	   int c;
9983 	
9984 	   assert(scip != NULL);
9985 	   assert(conshdlr != NULL);
9986 	   assert(conss != NULL || nconss == 0);
9987 	   assert(result != NULL);
9988 	
9989 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9990 	   assert(conshdlrdata != NULL);
9991 	
9992 	   *result = SCIP_FEASIBLE;
9993 	   soltag = SCIPgetExprNewSoltag(scip);
9994 	   maxviol = 0.0;
9995 	   maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
9996 	      && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING;
9997 	
9998 	   /* check nonlinear constraints for feasibility */
9999 	   for( c = 0; c < nconss; ++c )
10000	   {
10001	      assert(conss != NULL && conss[c] != NULL);
10002	      SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
10003	
10004	      if( isConsViolated(scip, conss[c]) )
10005	      {
10006	         *result = SCIP_INFEASIBLE;
10007	         maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
10008	
10009	         consdata = SCIPconsGetData(conss[c]);
10010	         assert(consdata != NULL);
10011	
10012	         /* print reason for infeasibility */
10013	         if( printreason )
10014	         {
10015	            SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
10016	            SCIPinfoMessage(scip, NULL, ";\n");
10017	
10018	            if( consdata->lhsviol > SCIPfeastol(scip) )
10019	            {
10020	               SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
10021	            }
10022	            if( consdata->rhsviol > SCIPfeastol(scip) )
10023	            {
10024	               SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
10025	            }
10026	         }
10027	         else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
10028	         {
10029	            /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
10030	            return SCIP_OKAY;
10031	         }
10032	
10033	         /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
10034	         if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
10035	            maypropfeasible = FALSE;
10036	
10037	         if( maypropfeasible )
10038	         {
10039	            if( consdata->lhsviol > SCIPfeastol(scip) )
10040	            {
10041	               /* check if there is a variable which may help to get the left hand side satisfied
10042	                * if there is no such variable, then we cannot get feasible
10043	                */
10044	               if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
10045	                   !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
10046	                  maypropfeasible = FALSE;
10047	            }
10048	            else
10049	            {
10050	               assert(consdata->rhsviol > SCIPfeastol(scip));
10051	               /* check if there is a variable which may help to get the right hand side satisfied
10052	                * if there is no such variable, then we cannot get feasible
10053	                */
10054	               if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
10055	                   !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
10056	                  maypropfeasible = FALSE;
10057	            }
10058	         }
10059	      }
10060	   }
10061	
10062	   if( *result == SCIP_INFEASIBLE && maypropfeasible )
10063	   {
10064	      SCIP_Bool success;
10065	
10066	      SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
10067	
10068	      /* do not pass solution to NLP heuristic if we made it feasible this way */
10069	      if( success )
10070	         return SCIP_OKAY;
10071	   }
10072	
10073	   if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
10074	   {
10075	      SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
10076	   }
10077	
10078	   return SCIP_OKAY;
10079	}
10080	
10081	
10082	/** domain propagation method of constraint handler */
10083	static
10084	SCIP_DECL_CONSPROP(consPropNonlinear)
10085	{  /*lint --e{715}*/
10086	   int nchgbds = 0;
10087	
10088	   SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
10089	   assert(nchgbds >= 0);
10090	
10091	   /* TODO would it make sense to check for redundant constraints? */
10092	
10093	   return SCIP_OKAY;
10094	}
10095	
10096	
10097	/** presolving method of constraint handler */
10098	static
10099	SCIP_DECL_CONSPRESOL(consPresolNonlinear)
10100	{  /*lint --e{715}*/
10101	   SCIP_CONSHDLRDATA* conshdlrdata;
10102	   SCIP_Bool infeasible;
10103	   int c;
10104	
10105	   *result = SCIP_DIDNOTFIND;
10106	
10107	   if( nconss == 0 )
10108	   {
10109	      *result = SCIP_DIDNOTRUN;
10110	      return SCIP_OKAY;
10111	   }
10112	
10113	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10114	   assert(conshdlrdata != NULL);
10115	
10116	   /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
10117	   SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
10118	   if( infeasible )
10119	   {
10120	      *result = SCIP_CUTOFF;
10121	      return SCIP_OKAY;
10122	   }
10123	
10124	   /* merge constraints with the same root expression */
10125	   if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
10126	   {
10127	      SCIP_Bool success;
10128	
10129	      SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
10130	      if( success )
10131	         *result = SCIP_SUCCESS;
10132	   }
10133	
10134	   /* propagate constraints */
10135	   SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
10136	   if( *result == SCIP_CUTOFF )
10137	      return SCIP_OKAY;
10138	
10139	   /* propagate function domains (TODO integrate with simplify?) */
10140	   if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
10141	   {
10142	      SCIP_RESULT localresult;
10143	      SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
10144	      if( localresult == SCIP_CUTOFF )
10145	      {
10146	         *result = SCIP_CUTOFF;
10147	         return SCIP_OKAY;
10148	      }
10149	      if( localresult == SCIP_REDUCEDDOM )
10150	         *result = SCIP_REDUCEDDOM;
10151	   }
10152	
10153	   /* check for redundant constraints, remove constraints that are a value expression */
10154	   SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
10155	   if( infeasible )
10156	   {
10157	      *result = SCIP_CUTOFF;
10158	      return SCIP_OKAY;
10159	   }
10160	
10161	   /* try to upgrade constraints */
10162	   for( c = 0; c < nconss; ++c )
10163	   {
10164	      SCIP_Bool upgraded;
10165	
10166	      /* skip inactive and deleted constraints */
10167	      if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
10168	         continue;
10169	
10170	      SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10171	   }
10172	
10173	   /* try to change continuous variables that appear linearly to be implicit integer */
10174	   if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
10175	   {
10176	      SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
10177	
10178	      if( infeasible )
10179	      {
10180	         SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
10181	         *result = SCIP_CUTOFF;
10182	         return SCIP_OKAY;
10183	      }
10184	   }
10185	
10186	   /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
10187	   if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) && SCIPisPresolveFinished(scip)
10188	      && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
10189	   {
10190	      /* run this presolving technique only once because we don't want to generate identical bound disjunction
10191	       * constraints multiple times
10192	       */
10193	      conshdlrdata->checkedvarlocks = TRUE;
10194	
10195	      for( c = 0; c < nconss; ++c )
10196	      {
10197	         int tmpnchgvartypes = 0;
10198	         int tmpnaddconss = 0;
10199	
10200	         SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
10201	         SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
10202	            SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
10203	
10204	         if( infeasible )
10205	         {
10206	            SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
10207	            *result = SCIP_CUTOFF;
10208	            return SCIP_OKAY;
10209	         }
10210	
10211	         (*nchgvartypes) += tmpnchgvartypes;
10212	         (*naddconss) += tmpnaddconss;
10213	      }
10214	   }
10215	
10216	   if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
10217	      *result = SCIP_SUCCESS;
10218	   else
10219	      *result = SCIP_DIDNOTFIND;
10220	
10221	   return SCIP_OKAY;
10222	}
10223	
10224	
10225	/** propagation conflict resolving method of constraint handler */
10226	#ifdef SCIP_DISABLED_CODE
10227	static
10228	SCIP_DECL_CONSRESPROP(consRespropNonlinear)
10229	{  /*lint --e{715}*/
10230	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10231	   SCIPABORT(); /*lint --e{527}*/
10232	
10233	   return SCIP_OKAY;
10234	}
10235	#else
10236	#define consRespropNonlinear NULL
10237	#endif
10238	
10239	
10240	/** variable rounding lock method of constraint handler */
10241	static
10242	SCIP_DECL_CONSLOCK(consLockNonlinear)
10243	{  /*lint --e{715}*/
10244	   SCIP_CONSDATA* consdata;
10245	   SCIP_EXPR_OWNERDATA* ownerdata;
10246	   SCIP_Bool reinitsolve = FALSE;
10247	
10248	   assert(conshdlr != NULL);
10249	   assert(cons != NULL);
10250	
10251	   consdata = SCIPconsGetData(cons);
10252	   assert(consdata != NULL);
10253	   assert(consdata->expr != NULL);
10254	
10255	   ownerdata = SCIPexprGetOwnerData(consdata->expr);
10256	
10257	   /* check whether we need to initSolve again because
10258	    * - we have enfo initialized (nenfos >= 0)
10259	    * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
10260	    */
10261	   if( ownerdata->nenfos >= 0 )
10262	   {
10263	      if( (consdata->nlockspos == 0) != (nlockspos == 0) )
10264	         reinitsolve = TRUE;
10265	      if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
10266	         reinitsolve = TRUE;
10267	   }
10268	
10269	   if( reinitsolve )
10270	   {
10271	      SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10272	   }
10273	
10274	   /* add locks */
10275	   SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
10276	
10277	   if( reinitsolve )
10278	   {
10279	      SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10280	   }
10281	
10282	   return SCIP_OKAY;
10283	}
10284	
10285	
10286	/** constraint activation notification method of constraint handler */
10287	static
10288	SCIP_DECL_CONSACTIVE(consActiveNonlinear)
10289	{  /*lint --e{715}*/
10290	   SCIP_CONSDATA* consdata;
10291	   SCIP_Bool infeasible = FALSE;
10292	
10293	   consdata = SCIPconsGetData(cons);
10294	   assert(consdata != NULL);
10295	
10296	   /* simplify root expression if the constraint has been added after presolving */
10297	   if( SCIPgetStage(scip) > SCIP_STAGE_EXITPRESOLVE )
10298	   {
10299	      SCIP_Bool replacedroot;
10300	
10301	      if( !consdata->issimplified )
10302	      {
10303	         SCIP_EXPR* simplified;
10304	         SCIP_Bool changed;
10305	
10306	         /* simplify constraint */
10307	         SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
10308	         SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
10309	         assert(simplified != NULL);
10310	         consdata->expr = simplified;
10311	         consdata->issimplified = TRUE;
10312	      }
10313	
10314	      /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
10315	      SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
10316	      assert(!replacedroot);  /* root expression cannot have been equal to one of its subexpressions */
10317	
10318	      /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
10319	      {
10320	         SCIP_CONSHDLRDATA* conshdlrdata;
10321	         SCIP_EXPRITER* it;
10322	         SCIP_EXPR* expr;
10323	
10324	         conshdlrdata = SCIPconshdlrGetData(conshdlr);
10325	         assert(conshdlrdata != NULL);
10326	
10327	         SCIP_CALL( SCIPcreateExpriter(scip, &it) );
10328	         SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
10329	         SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
10330	         for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10331	         {
10332	            SCIP_EXPR* child;
10333	            SCIP_EXPR* hashmapexpr;
10334	
10335	            child = SCIPexpriterGetChildExprDFS(it);
10336	            if( !SCIPisExprVar(scip, child) )
10337	               continue;
10338	
10339	            /* check which expression is stored in the hashmap for the var of child */
10340	            hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
10341	            /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
10342	            if( hashmapexpr != NULL && hashmapexpr != child )
10343	            {
10344	               SCIP_CALL( SCIPreplaceExprChild(scip, expr, SCIPexpriterGetChildIdxDFS(it), hashmapexpr) );
10345	            }
10346	         }
10347	         SCIPfreeExpriter(&it);
10348	      }
10349	   }
10350	
10351	   /* store variable expressions */
10352	   if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10353	   {
10354	      SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10355	   }
10356	
10357	   /* add manually locks to constraints that are not checked for feasibility */
10358	   if( !SCIPconsIsChecked(cons) )
10359	   {
10360	      assert(consdata->nlockspos == 0);
10361	      assert(consdata->nlocksneg == 0);
10362	
10363	      SCIP_CALL( addLocks(scip, cons, 1, 0) );
10364	   }
10365	
10366	   if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
10367	   {
10368	      SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10369	   }
10370	
10371	   /* TODO deal with infeasibility */
10372	   assert(!infeasible);
10373	
10374	   return SCIP_OKAY;
10375	}
10376	
10377	
10378	/** constraint deactivation notification method of constraint handler */
10379	static
10380	SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
10381	{  /*lint --e{715}*/
10382	   SCIP_CONSHDLRDATA* conshdlrdata;
10383	
10384	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10385	   assert(conshdlrdata != NULL);
10386	
10387	   if( SCIPgetStage(scip) < SCIP_STAGE_EXITSOLVE )
10388	   {
10389	      SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10390	   }
10391	
10392	   if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10393	   {
10394	      SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10395	      SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(cons)) );
10396	   }
10397	
10398	   /* remove locks that have been added in consActiveExpr() */
10399	   if( !SCIPconsIsChecked(cons) )
10400	   {
10401	      SCIP_CALL( addLocks(scip, cons, -1, 0) );
10402	
10403	      assert(SCIPconsGetData(cons)->nlockspos == 0);
10404	      assert(SCIPconsGetData(cons)->nlocksneg == 0);
10405	   }
10406	
10407	   return SCIP_OKAY;
10408	}
10409	
10410	
10411	/** constraint enabling notification method of constraint handler */
10412	static
10413	SCIP_DECL_CONSENABLE(consEnableNonlinear)
10414	{  /*lint --e{715}*/
10415	   SCIP_CONSHDLRDATA* conshdlrdata;
10416	
10417	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10418	   assert(conshdlrdata != NULL);
10419	
10420	   if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10421	   {
10422	      SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10423	   }
10424	
10425	   return SCIP_OKAY;
10426	}
10427	
10428	
10429	/** constraint disabling notification method of constraint handler */
10430	static
10431	SCIP_DECL_CONSDISABLE(consDisableNonlinear)
10432	{  /*lint --e{715}*/
10433	   SCIP_CONSHDLRDATA* conshdlrdata;
10434	
10435	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10436	   assert(conshdlrdata != NULL);
10437	
10438	   if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10439	   {
10440	      SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10441	   }
10442	
10443	   return SCIP_OKAY;
10444	}
10445	
10446	/** variable deletion of constraint handler */
10447	#ifdef SCIP_DISABLED_CODE
10448	static
10449	SCIP_DECL_CONSDELVARS(consDelvarsNonlinear)
10450	{  /*lint --e{715}*/
10451	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10452	   SCIPABORT(); /*lint --e{527}*/
10453	
10454	   return SCIP_OKAY;
10455	}
10456	#else
10457	#define consDelvarsNonlinear NULL
10458	#endif
10459	
10460	
10461	/** constraint display method of constraint handler */
10462	static
10463	SCIP_DECL_CONSPRINT(consPrintNonlinear)
10464	{  /*lint --e{715}*/
10465	   SCIP_CONSDATA* consdata;
10466	
10467	   consdata = SCIPconsGetData(cons);
10468	   assert(consdata != NULL);
10469	   assert(consdata->expr != NULL);
10470	
10471	   /* print left hand side for ranged constraints */
10472	   if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10473	   {
10474	      SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10475	   }
10476	
10477	   /* print expression */
10478	   SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
10479	
10480	   /* print right hand side */
10481	   if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10482	      SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
10483	   else if( !SCIPisInfinity(scip, consdata->rhs) )
10484	      SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
10485	   else if( !SCIPisInfinity(scip, -consdata->lhs) )
10486	      SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
10487	   else
10488	      SCIPinfoMessage(scip, file, " [free]");
10489	
10490	   return SCIP_OKAY;
10491	}
10492	
10493	
10494	/** constraint copying method of constraint handler */
10495	static
10496	SCIP_DECL_CONSCOPY(consCopyNonlinear)
10497	{  /*lint --e{715}*/
10498	   SCIP_CONSHDLR* targetconshdlr;
10499	   SCIP_EXPR* targetexpr = NULL;
10500	   SCIP_CONSDATA* sourcedata;
10501	
10502	   assert(cons != NULL);
10503	
10504	   sourcedata = SCIPconsGetData(sourcecons);
10505	   assert(sourcedata != NULL);
10506	
10507	   targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10508	   assert(targetconshdlr != NULL);
10509	
10510	   SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
10511	
10512	   if( targetexpr == NULL )
10513	      *valid = FALSE;
10514	
10515	   *cons = NULL;
10516	   if( *valid )
10517	   {
10518	      /* create copy (only capture targetexpr, no need to copy again) */
10519	      SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
10520	         targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
10521	         initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10522	   }
10523	
10524	   if( targetexpr != NULL )
10525	   {
10526	      /* release target expr */
10527	      SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
10528	   }
10529	
10530	   return SCIP_OKAY;
10531	}
10532	
10533	
10534	/** constraint parsing method of constraint handler */
10535	static
10536	SCIP_DECL_CONSPARSE(consParseNonlinear)
10537	{  /*lint --e{715}*/
10538	   SCIP_Real  lhs;
10539	   SCIP_Real  rhs;
10540	   const char* endptr;
10541	   SCIP_EXPR* consexprtree;
10542	
10543	   SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
10544	
10545	   assert(scip != NULL);
10546	   assert(success != NULL);
10547	   assert(str != NULL);
10548	   assert(name != NULL);
10549	   assert(cons != NULL);
10550	
10551	   *success = FALSE;
10552	
10553	   /* return if string empty */
10554	   if( !*str )
10555	      return SCIP_OKAY;
10556	
10557	   endptr = str;
10558	
10559	   /* set left and right hand side to their default values */
10560	   lhs = -SCIPinfinity(scip);
10561	   rhs =  SCIPinfinity(scip);
10562	
10563	   /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
10564	
10565	   /* check for left hand side */
10566	   if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
10567	   {
10568	      /* there is a number coming, maybe it is a left-hand-side */
10569	      if( !SCIPstrToRealValue(str, &lhs, (char**)&endptr) )
10570	      {
10571	         SCIPerrorMessage("error parsing number from <%s>\n", str);
10572	         return SCIP_READERROR;
10573	      }
10574	
10575	      /* ignore whitespace */
10576	      while( isspace((unsigned char)*endptr) )
10577	         ++endptr;
10578	
10579	      if( endptr[0] != '<' || endptr[1] != '=' )
10580	      {
10581	         /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
10582	         lhs = -SCIPinfinity(scip);
10583	      }
10584	      else
10585	      {
10586	         /* it was indeed a left-hand-side, so continue parsing after it */
10587	         str = endptr + 2;
10588	
10589	         /* ignore whitespace */
10590	         while( isspace((unsigned char)*str) )
10591	            ++str;
10592	      }
10593	   }
10594	
10595	   SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
10596	
10597	   /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
10598	   SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
10599	
10600	   /* check for left or right hand side */
10601	   while( isspace((unsigned char)*str) )
10602	      ++str;
10603	
10604	   /* check for free constraint */
10605	   if( strncmp(str, "[free]", 6) == 0 )
10606	   {
10607	      if( !SCIPisInfinity(scip, -lhs) )
10608	      {
10609	         SCIPerrorMessage("cannot have left hand side and [free] status \n");
10610	         SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10611	         return SCIP_OKAY;
10612	      }
10613	      *success = TRUE;
10614	   }
10615	   else
10616	   {
10617	      switch( *str )
10618	      {
10619	         case '<':
10620	            *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10621	            break;
10622	         case '=':
10623	            if( !SCIPisInfinity(scip, -lhs) )
10624	            {
10625	               SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
10626	               SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10627	               return SCIP_OKAY;
10628	            }
10629	            else
10630	            {
10631	               *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10632	               lhs = rhs;
10633	            }
10634	            break;
10635	         case '>':
10636	            if( !SCIPisInfinity(scip, -lhs) )
10637	            {
10638	               SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
10639	               SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10640	               return SCIP_OKAY;
10641	            }
10642	            else
10643	            {
10644	               *success = SCIPstrToRealValue(str+2, &lhs, (char**)&endptr);
10645	               break;
10646	            }
10647	         case '\0':
10648	            *success = TRUE;
10649	            break;
10650	         default:
10651	            SCIPerrorMessage("unexpected character %c\n", *str);
10652	            SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10653	            return SCIP_OKAY;
10654	      }
10655	   }
10656	
10657	   /* create constraint */
10658	   SCIP_CALL( createCons(scip, conshdlr, cons, name,
10659	      consexprtree, lhs, rhs, FALSE,
10660	      initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10661	   assert(*cons != NULL);
10662	
10663	   SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10664	
10665	   SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
10666	
10667	   return SCIP_OKAY;
10668	}
10669	
10670	
10671	/** constraint method of constraint handler which returns the variables (if possible) */
10672	static
10673	SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
10674	{  /*lint --e{715}*/
10675	   SCIP_CONSDATA* consdata;
10676	   int i;
10677	
10678	   consdata = SCIPconsGetData(cons);
10679	   assert(consdata != NULL);
10680	
10681	   /* store variable expressions if not done so far */
10682	   SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10683	
10684	   /* check whether array is too small in order to store all variables */
10685	   if( varssize < consdata->nvarexprs )
10686	   {
10687	      *success = FALSE;
10688	      return SCIP_OKAY;
10689	   }
10690	
10691	   for( i = 0; i < consdata->nvarexprs; ++i )
10692	   {
10693	      vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
10694	      assert(vars[i] != NULL);
10695	   }
10696	
10697	   *success = TRUE;
10698	
10699	   return SCIP_OKAY;
10700	}
10701	
10702	/** constraint method of constraint handler which returns the number of variables (if possible) */
10703	static
10704	SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
10705	{  /*lint --e{715}*/
10706	   SCIP_CONSDATA* consdata;
10707	
10708	   consdata = SCIPconsGetData(cons);
10709	   assert(consdata != NULL);
10710	
10711	   /* store variable expressions if not done so far */
10712	   SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10713	
10714	   *nvars = consdata->nvarexprs;
10715	   *success = TRUE;
10716	
10717	   return SCIP_OKAY;
10718	}
10719	
10720	/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
10721	#ifdef SCIP_DISABLED_CODE
10722	static
10723	SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsNonlinear)
10724	{  /*lint --e{715}*/
10725	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10726	   SCIPABORT(); /*lint --e{527}*/
10727	
10728	   return SCIP_OKAY;
10729	}
10730	#else
10731	#define consGetDiveBdChgsNonlinear NULL
10732	#endif
10733	
10734	/** output method of statistics table to output file stream 'file' */
10735	static
10736	SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
10737	{ /*lint --e{715}*/
10738	   SCIP_CONSHDLR* conshdlr;
10739	   SCIP_CONSHDLRDATA* conshdlrdata;
10740	
10741	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10742	   assert(conshdlr != NULL);
10743	
10744	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10745	   assert(conshdlrdata != NULL);
10746	
10747	   /* print statistics for constraint handler */
10748	   SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
10749	   SCIPinfoMessage(scip, file, "  enforce%-10s:", "");
10750	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
10751	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
10752	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
10753	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
10754	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
10755	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
10756	   SCIPinfoMessage(scip, file, "\n");
10757	   SCIPinfoMessage(scip, file, "  presolve%-9s: %-65s", "", "");
10758	   SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
10759	   SCIPinfoMessage(scip, file, "\n");
10760	
10761	   return SCIP_OKAY;
10762	}
10763	
10764	/** output method of statistics table to output file stream 'file' */
10765	static
10766	SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
10767	{ /*lint --e{715}*/
10768	   SCIP_CONSHDLR* conshdlr;
10769	   SCIP_CONSHDLRDATA* conshdlrdata;
10770	
10771	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10772	   assert(conshdlr != NULL);
10773	
10774	   /* skip nlhdlr table if there never were active nonlinear constraints */
10775	   if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
10776	      return SCIP_OKAY;
10777	
10778	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10779	   assert(conshdlrdata != NULL);
10780	
10781	   /* print statistics for nonlinear handlers */
10782	   SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
10783	
10784	   return SCIP_OKAY;
10785	}
10786	
10787	/** execution method of display nlhdlrs dialog */
10788	static
10789	SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
10790	{  /*lint --e{715}*/
10791	   SCIP_CONSHDLR* conshdlr;
10792	   SCIP_CONSHDLRDATA* conshdlrdata;
10793	   int i;
10794	
10795	   /* add dialog to history of dialogs that have been executed */
10796	   SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
10797	
10798	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10799	   assert(conshdlr != NULL);
10800	
10801	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10802	   assert(conshdlrdata != NULL);
10803	
10804	   /* display list of nonlinear handler */
10805	   SCIPdialogMessage(scip, NULL, "\n");
10806	   SCIPdialogMessage(scip, NULL, " nonlinear handler  enabled  detectprio  enforceprio  description\n");
10807	   SCIPdialogMessage(scip, NULL, " -----------------  -------  ----------  -----------  -----------\n");
10808	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10809	   {
10810	      SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
10811	      assert(nlhdlr != NULL);
10812	
10813	      SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
10814	      SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
10815	      SCIPdialogMessage(scip, NULL, " %10d ", SCIPnlhdlrGetDetectPriority(nlhdlr));
10816	      SCIPdialogMessage(scip, NULL, " %11d ", SCIPnlhdlrGetEnfoPriority(nlhdlr));
10817	      SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
10818	      SCIPdialogMessage(scip, NULL, "\n");
10819	   }
10820	   SCIPdialogMessage(scip, NULL, "\n");
10821	
10822	   /* next dialog will be root dialog again */
10823	   *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
10824	
10825	   return SCIP_OKAY;
10826	}
10827	
10828	/*
10829	 * constraint handler specific interface methods
10830	 */
10831	
10832	/** creates the handler for nonlinear constraints and includes it in SCIP */
10833	SCIP_RETCODE SCIPincludeConshdlrNonlinear(
10834	   SCIP*                 scip                /**< SCIP data structure */
10835	   )
10836	{
10837	   SCIP_CONSHDLRDATA* conshdlrdata;
10838	   SCIP_DIALOG* parentdialog;
10839	
10840	   /* create nonlinear constraint handler data */
(1) Event alloc_fn: Storage is returned from allocation function "BMSallocClearMemory_call". [details]
(2) Event var_assign: Assigning: "conshdlrdata" = storage returned from "BMSallocClearMemory_call(1UL, 616UL, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/cons_nonlinear.c", 10841)".
(3) Event cond_false: Condition "(conshdlrdata = BMSallocClearMemory_call(1UL /* (size_t)1 */, 616UL /* sizeof (*conshdlrdata) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/cons_nonlinear.c", 10841)) == NULL", taking false branch.
(4) Event cond_false: Condition "(_restat_ = (((conshdlrdata = BMSallocClearMemory_call(1UL /* (size_t)1 */, 616UL /* sizeof (*conshdlrdata) */, "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/scip/src/scip/cons_nonlinear.c", 10841)) == NULL) ? SCIP_NOMEMORY : SCIP_OKAY)) != SCIP_OKAY", taking false branch.
(5) Event if_end: End of if statement.
Also see events: [leaked_storage]
10841	   SCIP_CALL( SCIPallocClearMemory(scip, &conshdlrdata) );
10842	   conshdlrdata->intevalvar = intEvalVarBoundTightening;
10843	   conshdlrdata->curboundstag = 1;
10844	   conshdlrdata->lastboundrelax = 1;
10845	   conshdlrdata->curpropboundstag = 1;
10846	   conshdlrdata->newsoleventfilterpos = -1;
(6) Event cond_false: Condition "(_restat_ = SCIPcreateClock(scip, &conshdlrdata->canonicalizetime)) != SCIP_OKAY", taking false branch.
(7) Event if_end: End of if statement.
10847	   SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
(8) Event cond_false: Condition "(_restat_ = SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.)) != SCIP_OKAY", taking false branch.
(9) Event if_end: End of if statement.
10848	   SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
(10) Event cond_true: Condition "(_restat_ = SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100)) != SCIP_OKAY", taking true branch.
(11) Event leaked_storage: Variable "conshdlrdata" going out of scope leaks the storage it points to.
Also see events: [alloc_fn][var_assign]
10849	   SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
10850	
10851	   /* include constraint handler */
10852	   SCIP_CALL( SCIPincludeConshdlr(scip, CONSHDLR_NAME, CONSHDLR_DESC,
10853	         CONSHDLR_SEPAPRIORITY, CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY,
10854	         CONSHDLR_SEPAFREQ, CONSHDLR_PROPFREQ, CONSHDLR_EAGERFREQ, CONSHDLR_MAXPREROUNDS,
10855	         CONSHDLR_DELAYSEPA, CONSHDLR_DELAYPROP, CONSHDLR_NEEDSCONS,
10856	         CONSHDLR_PROP_TIMING, CONSHDLR_PRESOLTIMING,
10857	         conshdlrCopyNonlinear,
10858	         consFreeNonlinear, consInitNonlinear, consExitNonlinear,
10859	         consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
10860	         consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
10861	         consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
10862	         consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
10863	         consActiveNonlinear, consDeactiveNonlinear,
10864	         consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
10865	         consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
10866	         consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, conshdlrdata) );
10867	
10868	   /* add nonlinear constraint handler parameters */
10869	   /* TODO organize into more subcategories */
10870	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
10871	         "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
10872	         &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
10873	
10874	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
10875	         "whether to check bounds of all auxiliary variable to seed reverse propagation",
10876	         &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
10877	
10878	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
10879	         "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",
10880	         &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
10881	
10882	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
10883	         "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
10884	         &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10885	
10886	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
10887	         "by how much to relax constraint sides during bound tightening",
10888	         &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10889	
10890	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
10891	         "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
10892	         &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
10893	
10894	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
10895	         "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
10896	         &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
10897	
10898	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
10899	         "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
10900	         &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
10901	
10902	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
10903	           "maximal number of auxiliary expressions per bilinear term",
10904	           &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
10905	
10906	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
10907	         "whether to reformulate products of binary variables during presolving",
10908	         &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
10909	
10910	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
10911	         "whether to use the AND constraint handler for reformulating binary products",
10912	         &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
10913	
10914	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
10915	         "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
10916	         &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
10917	
10918	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
10919	         "whether to forbid multiaggregation of nonlinear variables",
10920	         &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
10921	
10922	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
10923	         "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
10924	         &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
10925	
10926	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
10927	         "whether to (re)run propagation in enforcement",
10928	         &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
10929	
10930	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
10931	         "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
10932	         &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
10933	
10934	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
10935	         "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
10936	         &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
10937	
10938	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
10939	         "consider efficacy requirement when deciding whether a cut is \"strong\"",
10940	         &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
10941	
10942	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
10943	         "whether to force \"strong\" cuts in enforcement",
10944	         &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
10945	
10946	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
10947	         "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
10948	         &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
10949	
10950	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
10951	         "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
10952	         &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
10953	
10954	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
10955	         "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",
10956	         &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
10957	
10958	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
10959	         "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
10960	         &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
10961	
10962	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
10963	         "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)",
10964	         &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
10965	
10966	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
10967	         "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
10968	         &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
10969	
10970	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
10971	         "whether to use external branching candidates and branching rules for branching",
10972	         &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
10973	
10974	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
10975	         "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
10976	         &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
10977	
10978	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
10979	         "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
10980	         &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
10981	
10982	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
10983	         "weight by how much to consider the violation assigned to a variable for its branching score",
10984	         &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10985	
10986	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
10987	         "weight by how much to consider the dual values of rows that contain a variable for its branching score",
10988	         &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10989	
10990	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
10991	         "weight by how much to consider the pseudo cost of a variable for its branching score",
10992	         &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10993	
10994	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
10995	         "weight by how much to consider the domain width in branching score",
10996	         &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10997	
10998	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
10999	         "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
11000	         &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
11001	
11002	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
11003	         "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
11004	         &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
11005	
11006	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
11007	         "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
11008	         &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
11009	
11010	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
11011	         "minimum pseudo-cost update count required to consider pseudo-costs reliable",
11012	         &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11013	
11014	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
11015	         "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)",
11016	         &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
11017	
11018	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
11019	         "whether to assume that any constraint is convex",
11020	         &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
11021	
11022	   /* include handler for bound change events */
11023	   SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
11024	         "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
11025	   assert(conshdlrdata->eventhdlr != NULL);
11026	
11027	   /* include tables for statistics */
11028	   assert(SCIPfindTable(scip, TABLE_NAME_NONLINEAR) == NULL);
11029	   SCIP_CALL( SCIPincludeTable(scip, TABLE_NAME_NONLINEAR, TABLE_DESC_NONLINEAR, FALSE,
11030	         NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
11031	         NULL, TABLE_POSITION_NONLINEAR, TABLE_EARLIEST_STAGE_NONLINEAR) );
11032	
11033	   assert(SCIPfindTable(scip, TABLE_NAME_NLHDLR) == NULL);
11034	   SCIP_CALL( SCIPincludeTable(scip, TABLE_NAME_NLHDLR, TABLE_DESC_NLHDLR, TRUE,
11035	         NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
11036	         NULL, TABLE_POSITION_NLHDLR, TABLE_EARLIEST_STAGE_NLHDLR) );
11037	
11038	   /* create, include, and release display nlhdlrs dialog */
11039	   if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
11040	   {
11041	      SCIP_DIALOG* dialog;
11042	
11043	      assert(parentdialog != NULL);
11044	      assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
11045	
11046	      SCIP_CALL( SCIPincludeDialog(scip, &dialog,
11047	            NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
11048	            DIALOG_NAME, DIALOG_DESC, DIALOG_ISSUBMENU, NULL) );
11049	      SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
11050	      SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
11051	   }
11052	
11053	   SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
11054	         processNewSolutionEvent, NULL) );
11055	
11056	   return SCIP_OKAY;
11057	}
11058	
11059	/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
11060	SCIP_RETCODE SCIPincludeConsUpgradeNonlinear(
11061	   SCIP*                 scip,               /**< SCIP data structure */
11062	   SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)),  /**< method to call for upgrading nonlinear constraint */
11063	   int                   priority,           /**< priority of upgrading method */
11064	   SCIP_Bool             active,             /**< should the upgrading method by active by default? */
11065	   const char*           conshdlrname        /**< name of the constraint handler */
11066	   )
11067	{
11068	   SCIP_CONSHDLR*     conshdlr;
11069	   SCIP_CONSHDLRDATA* conshdlrdata;
11070	   CONSUPGRADE*       consupgrade;
11071	   char               paramname[SCIP_MAXSTRLEN];
11072	   char               paramdesc[SCIP_MAXSTRLEN];
11073	   int                i;
11074	
11075	   assert(conshdlrname != NULL );
11076	   assert(nlconsupgd != NULL);
11077	
11078	   /* find the nonlinear constraint handler */
11079	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11080	   if( conshdlr == NULL )
11081	   {
11082	      SCIPerrorMessage("nonlinear constraint handler not found\n");
11083	      return SCIP_PLUGINNOTFOUND;
11084	   }
11085	
11086	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11087	   assert(conshdlrdata != NULL);
11088	
11089	   /* check whether upgrade method exists already */
11090	   for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
11091	   {
11092	      if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
11093	      {
11094	#ifdef SCIP_DEBUG
11095	         SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
11096	#endif
11097	         return SCIP_OKAY;
11098	      }
11099	   }
11100	
11101	   /* create a nonlinear constraint upgrade data object */
11102	   SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
11103	   consupgrade->consupgd = nlconsupgd;
11104	   consupgrade->priority = priority;
11105	   consupgrade->active   = active;
11106	
11107	   /* insert nonlinear constraint upgrade method into constraint handler data */
11108	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
11109	   assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
11110	
11111	   for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
11112	      conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
11113	   assert(0 <= i && i <= conshdlrdata->nconsupgrades);
11114	   conshdlrdata->consupgrades[i] = consupgrade;
11115	   conshdlrdata->nconsupgrades++;
11116	
11117	   /* adds parameter to turn on and off the upgrading step */
11118	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
11119	   (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
11120	   SCIP_CALL( SCIPaddBoolParam(scip,
11121	         paramname, paramdesc,
11122	         &consupgrade->active, FALSE, active, NULL, NULL) );
11123	
11124	   return SCIP_OKAY;
11125	}
11126	
11127	/** creates and captures a nonlinear constraint
11128	 *
11129	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11130	 */
11131	SCIP_RETCODE SCIPcreateConsNonlinear(
11132	   SCIP*                 scip,               /**< SCIP data structure */
11133	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11134	   const char*           name,               /**< name of constraint */
11135	   SCIP_EXPR*            expr,               /**< expression of constraint (must not be NULL) */
11136	   SCIP_Real             lhs,                /**< left hand side of constraint */
11137	   SCIP_Real             rhs,                /**< right hand side of constraint */
11138	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
11139	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11140	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
11141	                                              *   Usually set to TRUE. */
11142	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
11143	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11144	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
11145	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11146	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
11147	                                              *   Usually set to TRUE. */
11148	   SCIP_Bool             local,              /**< is constraint only valid locally?
11149	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11150	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
11151	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
11152	                                              *   adds coefficients to this constraint. */
11153	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
11154	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
11155	                                              *   are separated as constraints. */
11156	   SCIP_Bool             removable           /**< should the relaxation be removed from the LP due to aging or cleanup?
11157	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11158	   )
11159	{
11160	   /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
11161	   SCIP_CONSHDLR* conshdlr;
11162	
11163	   /* find the nonlinear constraint handler */
11164	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11165	   if( conshdlr == NULL )
11166	   {
11167	      SCIPerrorMessage("nonlinear constraint handler not found\n");
11168	      return SCIP_PLUGINNOTFOUND;
11169	   }
11170	
11171	   /* create constraint */
11172	   SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
11173	      initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11174	
11175	   return SCIP_OKAY;
11176	}
11177	
11178	/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
11179	 *
11180	 *  All flags can be set via SCIPconsSetFLAGNAME-methods.
11181	 *
11182	 *  @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
11183	 *
11184	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11185	 */
11186	SCIP_RETCODE SCIPcreateConsBasicNonlinear(
11187	   SCIP*                 scip,               /**< SCIP data structure */
11188	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11189	   const char*           name,               /**< name of constraint */
11190	   SCIP_EXPR*            expr,               /**< expression of constraint (must not be NULL) */
11191	   SCIP_Real             lhs,                /**< left hand side of constraint */
11192	   SCIP_Real             rhs                 /**< right hand side of constraint */
11193	   )
11194	{
11195	   SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
11196	         TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11197	
11198	   return SCIP_OKAY;
11199	}
11200	
11201	/** creates and captures a quadratic nonlinear constraint
11202	 *
11203	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11204	 */
11205	SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(
11206	   SCIP*                 scip,               /**< SCIP data structure */
11207	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11208	   const char*           name,               /**< name of constraint */
11209	   int                   nlinvars,           /**< number of linear terms */
11210	   SCIP_VAR**            linvars,            /**< array with variables in linear part */
11211	   SCIP_Real*            lincoefs,           /**< array with coefficients of variables in linear part */
11212	   int                   nquadterms,         /**< number of quadratic terms */
11213	   SCIP_VAR**            quadvars1,          /**< array with first variables in quadratic terms */
11214	   SCIP_VAR**            quadvars2,          /**< array with second variables in quadratic terms */
11215	   SCIP_Real*            quadcoefs,          /**< array with coefficients of quadratic terms */
11216	   SCIP_Real             lhs,                /**< left hand side of quadratic equation */
11217	   SCIP_Real             rhs,                /**< right hand side of quadratic equation */
11218	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
11219	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11220	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
11221	                                              *   Usually set to TRUE. */
11222	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
11223	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11224	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
11225	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11226	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
11227	                                              *   Usually set to TRUE. */
11228	   SCIP_Bool             local,              /**< is constraint only valid locally?
11229	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11230	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
11231	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
11232	                                              *   adds coefficients to this constraint. */
11233	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
11234	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
11235	                                              *   are separated as constraints. */
11236	   SCIP_Bool             removable           /**< should the relaxation be removed from the LP due to aging or cleanup?
11237	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11238	   )
11239	{
11240	   SCIP_CONSHDLR* conshdlr;
11241	   SCIP_EXPR* expr;
11242	
11243	   assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
11244	   assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
11245	
11246	   /* get nonlinear constraint handler */
11247	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11248	   if( conshdlr == NULL )
11249	   {
11250	      SCIPerrorMessage("nonlinear constraint handler not found\n");
11251	      return SCIP_PLUGINNOTFOUND;
11252	   }
11253	
11254	   /* create quadratic expression */
11255	   SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
11256	   assert(expr != NULL);
11257	
11258	   /* create nonlinear constraint */
11259	   SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
11260	      initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11261	
11262	   /* release quadratic expression (captured by constraint now) */
11263	   SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11264	
11265	   return SCIP_OKAY;
11266	}
11267	
11268	/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
11269	 *
11270	 *  All flags can be set via SCIPconsSetFLAGNAME-methods.
11271	 *
11272	 *  @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
11273	 *
11274	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11275	 */
11276	SCIP_RETCODE SCIPcreateConsBasicQuadraticNonlinear(
11277	   SCIP*                 scip,               /**< SCIP data structure */
11278	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11279	   const char*           name,               /**< name of constraint */
11280	   int                   nlinvars,           /**< number of linear terms */
11281	   SCIP_VAR**            linvars,            /**< array with variables in linear part */
11282	   SCIP_Real*            lincoefs,           /**< array with coefficients of variables in linear part */
11283	   int                   nquadterms,         /**< number of quadratic terms */
11284	   SCIP_VAR**            quadvars1,          /**< array with first variables in quadratic terms */
11285	   SCIP_VAR**            quadvars2,          /**< array with second variables in quadratic terms */
11286	   SCIP_Real*            quadcoefs,          /**< array with coefficients of quadratic terms */
11287	   SCIP_Real             lhs,                /**< left hand side of quadratic equation */
11288	   SCIP_Real             rhs                 /**< right hand side of quadratic equation */
11289	   )
11290	{
11291	   SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11292	      TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11293	
11294	   return SCIP_OKAY;
11295	}
11296	
11297	/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
11298	 *
11299	 * \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$
11300	 *
11301	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11302	 */
11303	SCIP_RETCODE SCIPcreateConsBasicSOCNonlinear(
11304	   SCIP*                 scip,               /**< SCIP data structure */
11305	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11306	   const char*           name,               /**< name of constraint */
11307	   int                   nvars,              /**< number of variables on left hand side of constraint (n) */
11308	   SCIP_VAR**            vars,               /**< array with variables on left hand side (x_i) */
11309	   SCIP_Real*            coefs,              /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
11310	   SCIP_Real*            offsets,            /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
11311	   SCIP_Real             constant,           /**< constant on left hand side (gamma) */
11312	   SCIP_VAR*             rhsvar,             /**< variable on right hand side of constraint (x_{n+1}) */
11313	   SCIP_Real             rhscoeff,           /**< coefficient of variable on right hand side (alpha_{n+1}) */
11314	   SCIP_Real             rhsoffset           /**< offset of variable on right hand side (beta_{n+1}) */
11315	   )
11316	{
11317	   SCIP_EXPR* expr;
11318	   SCIP_EXPR* lhssum;
11319	   SCIP_EXPR* terms[2];
11320	   SCIP_Real termcoefs[2];
11321	   int i;
11322	
11323	   assert(vars != NULL || nvars == 0);
11324	
11325	   SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) );  /* gamma */
11326	   for( i = 0; i < nvars; ++i )
11327	   {
11328	      SCIP_EXPR* varexpr;
11329	      SCIP_EXPR* powexpr;
11330	
11331	      SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) );   /* x_i */
11332	      if( offsets != NULL && offsets[i] != 0.0 )
11333	      {
11334	         SCIP_EXPR* sum;
11335	         SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) );  /* x_i + beta_i */
11336	         SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) );   /* (x_i + beta_i)^2 */
11337	         SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
11338	      }
11339	      else
11340	      {
11341	         SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) );  /* x_i^2 */
11342	      }
11343	
11344	      SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) );  /* + alpha_i^2 (x_i + beta_i)^2 */
11345	      SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
11346	      SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
11347	   }
11348	
11349	   SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) );  /* sqrt(...) */
11350	   SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
11351	   termcoefs[0] = 1.0;
11352	
11353	   SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) );  /* x_{n+1} */
11354	   termcoefs[1] = -rhscoeff;
11355	
11356	   SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) );  /* sqrt(...) - alpha_{n+1}x_{n_1} */
11357	
11358	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11359	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11360	
11361	   SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
11362	
11363	   SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11364	
11365	   return SCIP_OKAY;
11366	}
11367	
11368	/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
11369	 *
11370	 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
11371	 *
11372	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11373	 */
11374	SCIP_RETCODE SCIPcreateConsBasicSignpowerNonlinear(
11375	   SCIP*                 scip,               /**< SCIP data structure */
11376	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11377	   const char*           name,               /**< name of constraint */
11378	   SCIP_VAR*             x,                  /**< nonlinear variable x in constraint */
11379	   SCIP_VAR*             z,                  /**< linear variable z in constraint */
11380	   SCIP_Real             exponent,           /**< exponent n of |x+offset|^n term in constraint */
11381	   SCIP_Real             xoffset,            /**< offset in |x+offset|^n term in constraint */
11382	   SCIP_Real             zcoef,              /**< coefficient of z in constraint */
11383	   SCIP_Real             lhs,                /**< left hand side of constraint */
11384	   SCIP_Real             rhs                 /**< right hand side of constraint */
11385	   )
11386	{
11387	   SCIP_EXPR* xexpr;
11388	   SCIP_EXPR* terms[2];
11389	   SCIP_Real coefs[2];
11390	   SCIP_EXPR* sumexpr;
11391	
11392	   assert(x != NULL);
11393	   assert(z != NULL);
11394	
11395	   SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
11396	   if( xoffset != 0.0 )
11397	   {
11398	      SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
11399	      SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
11400	
11401	      SCIP_CALL( SCIPreleaseExpr(scip,  &sumexpr) );
11402	   }
11403	   else
11404	   {
11405	      SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) );  /* signpow(x, exponent) */
11406	   }
11407	   coefs[0] = 1.0;
11408	
11409	   SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
11410	   coefs[1] = zcoef;
11411	
11412	   SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) );  /* signpowexpr + zcoef * z */
11413	
11414	   SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
11415	
11416	   SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11417	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11418	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11419	   SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
11420	
11421	   return SCIP_OKAY;
11422	}
11423	
11424	/** gets tag indicating current local variable bounds */
11425	SCIP_Longint SCIPgetCurBoundsTagNonlinear(
11426	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11427	   )
11428	{
11429	   SCIP_CONSHDLRDATA* conshdlrdata;
11430	
11431	   assert(conshdlr != NULL);
11432	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11433	
11434	   return conshdlrdata->curboundstag;
11435	}
11436	
11437	/** gets the `curboundstag` from the last time where variable bounds were relaxed */
11438	SCIP_Longint SCIPgetLastBoundRelaxTagNonlinear(
11439	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11440	   )
11441	{
11442	   SCIP_CONSHDLRDATA* conshdlrdata;
11443	
11444	   assert(conshdlr != NULL);
11445	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11446	
11447	   return conshdlrdata->lastboundrelax;
11448	}
11449	
11450	/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
11451	 *
11452	 * @attention This method is not intended for normal use.
11453	 *   These tags are maintained by the event handler for variable bound change events.
11454	 *   This method is used by some unittests.
11455	 */
11456	void SCIPincrementCurBoundsTagNonlinear(
11457	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
11458	   SCIP_Bool             boundrelax          /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
11459	   )
11460	{
11461	   SCIP_CONSHDLRDATA* conshdlrdata;
11462	
11463	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11464	   assert(conshdlrdata != NULL);
11465	
11466	   ++conshdlrdata->curboundstag;
11467	   assert(conshdlrdata->curboundstag > 0);
11468	
11469	   if( boundrelax )
11470	      conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
11471	}
11472	
11473	/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
11474	SCIP_HASHMAP* SCIPgetVarExprHashmapNonlinear(
11475	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11476	   )
11477	{
11478	   assert(conshdlr != NULL);
11479	
11480	   return SCIPconshdlrGetData(conshdlr)->var2expr;
11481	}
11482	
11483	/** processes a rowprep for cut addition and maybe report branchscores */
11484	SCIP_RETCODE SCIPprocessRowprepNonlinear(
11485	   SCIP*                 scip,               /**< SCIP data structure */
11486	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler which provided the estimator */
11487	   SCIP_CONS*            cons,               /**< nonlinear constraint */
11488	   SCIP_EXPR*            expr,               /**< expression */
11489	   SCIP_ROWPREP*         rowprep,            /**< cut to be added */
11490	   SCIP_Bool             overestimate,       /**< whether the expression needs to be over- or underestimated */
11491	   SCIP_VAR*             auxvar,             /**< auxiliary variable */
11492	   SCIP_Real             auxvalue,           /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
11493	   SCIP_Bool             allowweakcuts,      /**< whether we should only look for "strong" cuts, or anything that separates is fine */
11494	   SCIP_Bool             branchscoresuccess, /**< whether the estimator generation generated branching scores */
11495	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement, or only in separation */
11496	   SCIP_SOL*             sol,                /**< solution to be separated (NULL for the LP solution) */
11497	   SCIP_RESULT*          result              /**< pointer to store the result */
11498	   )
11499	{
11500	   SCIP_Real cutviol;
11501	   SCIP_CONSHDLRDATA* conshdlrdata;
11502	   SCIP_Real auxvarvalue = SCIP_INVALID;
11503	   SCIP_Bool sepasuccess;
11504	   SCIP_Real estimateval = SCIP_INVALID;
11505	   SCIP_Real mincutviolation;
11506	
11507	   assert(nlhdlr != NULL);
11508	   assert(cons != NULL);
11509	   assert(expr != NULL);
11510	   assert(rowprep != NULL);
11511	   assert(auxvar != NULL);
11512	   assert(result != NULL);
11513	
11514	   /* decide on minimal violation of cut */
11515	   if( sol == NULL )
11516	      mincutviolation = SCIPgetLPFeastol(scip);  /* we enforce an LP solution */
11517	   else
11518	      mincutviolation = SCIPfeastol(scip);
11519	
11520	   conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11521	   assert(conshdlrdata != NULL);
11522	
11523	   sepasuccess = TRUE;
11524	
11525	   cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
11526	   if( cutviol > 0.0 )
11527	   {
11528	      auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
11529	
11530	      /* check whether cut is weak (if f(x) not defined, then it's never weak) */
11531	      if( !allowweakcuts && auxvalue != SCIP_INVALID )
11532	      {
11533	         /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
11534	          * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
11535	          * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
11536	          * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
11537	          * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
11538	          *   <->   c'x-b - z <= weakcutthreshold * (f(x)-z)
11539	          *
11540	          * if we are overestimating, we have z >= c'x-b >= f(x)
11541	          * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
11542	          * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
11543	          *   <->   c'x-b - z >= weakcutthreshold * (f(x)-z)
11544	          *
11545	          * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
11546	          */
11547	         if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11548	             ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11549	         {
11550	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s succeeded, but cut is too "\
11551	                           "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11552	                                     SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11553	                                     auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
11554	            sepasuccess = FALSE;
11555	         }
11556	      }
11557	
11558	      /* save estimator value for later, see long comment above why this gives the value for c'x-b */
11559	      estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
11560	   }
11561	   else
11562	   {
11563	      sepasuccess = FALSE;
11564	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s succeeded, but cut does not "\
11565	                     "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
11566	   }
11567	
11568	   /* clean up estimator */
11569	   if( sepasuccess )
11570	   {
11571	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s succeeded: auxvarvalue %g "\
11572	                     "estimateval %g auxvalue %g (over %d)\n    ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11573	                               auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
11574	                       SCIPprintRowprep(scip, rowprep, enfologfile); )
11575	
11576	      /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
11577	       * instead, may even scale them down, that is, scale so that max coef is close to 1
11578	       */
11579	      if( !allowweakcuts )
11580	      {
11581	         SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
11582	
11583	         if( !sepasuccess )
11584	         {
11585	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cleanup cut failed due to bad numerics\n"); )
11586	         }
11587	         else
11588	         {
11589	            cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
11590	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cleanup succeeded, violation = %g and %sreliable, "\
11591	                           "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
11592	            if( sepasuccess )
11593	               sepasuccess = cutviol > mincutviolation;
11594	         }
11595	
11596	         if( sepasuccess && auxvalue != SCIP_INVALID )
11597	         {
11598	            /* check whether cut is weak now
11599	             * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
11600	             * reconstructing estimateval from cutviol (TODO improve or remove?)
11601	             */
11602	            SCIP_Real auxvarcoef = 0.0;
11603	            int i;
11604	
11605	            /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
11606	             * it should be...
11607	             */
11608	            for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
11609	            {
11610	               if( SCIProwprepGetVars(rowprep)[i] == auxvar )
11611	               {
11612	                  auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
11613	                  break;
11614	               }
11615	            }
11616	
11617	            if( auxvarcoef == 0.0 ||
11618	                (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11619	                ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11620	            {
11621	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11622	                  auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
11623	               sepasuccess = FALSE;
11624	            }
11625	         }
11626	      }
11627	      else
11628	      {
11629	         /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
11630	
11631	         /* if estimate didn't report branchscores explicitly, then consider branching on those children for
11632	          * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
11633	          */
11634	         if( !branchscoresuccess )
11635	            SCIProwprepRecordModifications(rowprep);
11636	
11637	         SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
11638	
11639	         if( !sepasuccess )
11640	         {
11641	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cleanup failed, %d coefs modified, cutviol %g\n",
11642	                                     SCIProwprepGetNModifiedVars(rowprep), cutviol); )
11643	         }
11644	
11645	         /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
11646	          * changed
11647	          */
11648	         if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
11649	         {
11650	            SCIP_Real violscore;
11651	
11652	#ifdef BRSCORE_ABSVIOL
11653	            violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
11654	#else
11655	            SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
11656	#endif
11657	            SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
11658	
11659	            /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
11660	             * - were fixed,
11661	             * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
11662	             * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
11663	             * the first case came up again in #3085 and I don't see how to exclude this in the assert,
11664	             * so I'm disabling the assert for now
11665	             */
11666	            /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
11667	                  strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
11668	         }
11669	      }
11670	   }
11671	
11672	   /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
11673	   if( sepasuccess )
11674	   {
11675	      SCIP_ROW* row;
11676	
11677	      if( conshdlrdata->branchdualweight > 0.0 )
11678	      {
11679	         /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
11680	          * skip if gap is zero
11681	          */
11682	         if( auxvalue == SCIP_INVALID )
11683	            strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
11684	         else if( !SCIPisEQ(scip, auxvalue, estimateval) )
11685	         {
11686	            char gap[40];
11687	            (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
11688	            strcat(SCIProwprepGetName(rowprep), gap);
11689	         }
11690	      }
11691	
11692	      SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
11693	
11694	      if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
11695	      {
11696	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cut efficacy %g is too low (minefficacy=%g)\n",
11697	                                  SCIPgetCutEfficacy(scip, sol, row), SCIPgetSepaMinEfficacy(scip)); )
11698	      }
11699	      else if( !SCIPisCutApplicable(scip, row) )
11700	      {
11701	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cut not applicable (e.g., cut is boundchange below eps)\n"); )
11702	      }
11703	      else
11704	      {
11705	         SCIP_Bool infeasible;
11706	
11707	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    adding cut ");
11708	           SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
11709	
11710	         /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
11711	          * if we haven't found strong cuts before)
11712	          */
11713	         SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
11714	
11715	         /* mark row as not removable from LP for current node (this can prevent some cycling) */
11716	         if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
11717	            SCIPmarkRowNotRemovableLocal(scip, row);
11718	
11719	         if( infeasible )
11720	         {
11721	            *result = SCIP_CUTOFF;
11722	            SCIPnlhdlrIncrementNCutoffs(nlhdlr);
11723	         }
11724	         else
11725	         {
11726	            *result = SCIP_SEPARATED;
11727	            SCIPnlhdlrIncrementNSeparated(nlhdlr);
11728	         }
11729	      }
11730	
11731	      SCIP_CALL( SCIPreleaseRow(scip, &row) );
11732	   }
11733	   else if( branchscoresuccess )
11734	   {
11735	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    separation with estimate of nlhdlr %s failed, but "\
11736	                     "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
11737	
11738	      /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
11739	       * expressions eligible for branching candidate, see enforceConstraints() and branching()
11740	       */
11741	      *result = SCIP_BRANCHED;
11742	   }
11743	   else
11744	   {
11745	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    separation with estimate of nlhdlr %s failed and no "\
11746	                     "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
11747	                                                                                    " (!)" : ""); )
11748	   }
11749	
11750	   return SCIP_OKAY;
11751	}
11752	
11753	/** returns whether all nonlinear constraints are assumed to be convex */
11754	SCIP_Bool SCIPassumeConvexNonlinear(
11755	   SCIP_CONSHDLR*        conshdlr
11756	   )
11757	{
11758	   SCIP_CONSHDLRDATA* conshdlrdata;
11759	
11760	   assert(conshdlr != NULL);
11761	
11762	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11763	   assert(conshdlrdata != NULL);
11764	
11765	   return conshdlrdata->assumeconvex;
11766	}
11767	
11768	/** collects all bilinear terms for a given set of constraints
11769	 *
11770	 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
11771	 *       SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
11772	 */
11773	SCIP_RETCODE SCIPcollectBilinTermsNonlinear(
11774	   SCIP*                 scip,               /**< SCIP data structure */
11775	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
11776	   SCIP_CONS**           conss,              /**< nonlinear constraints */
11777	   int                   nconss              /**< total number of nonlinear constraints */
11778	   )
11779	{
11780	   assert(conshdlr != NULL);
11781	   assert(conss != NULL || nconss == 0);
11782	
11783	   SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11784	
11785	   return SCIP_OKAY;
11786	}
11787	
11788	/** returns the total number of bilinear terms that are contained in all nonlinear constraints
11789	 *
11790	 *  @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11791	 */
11792	int SCIPgetNBilinTermsNonlinear(
11793	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11794	   )
11795	{
11796	   SCIP_CONSHDLRDATA* conshdlrdata;
11797	
11798	   assert(conshdlr != NULL);
11799	
11800	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11801	   assert(conshdlrdata != NULL);
11802	
11803	   return conshdlrdata->nbilinterms;
11804	}
11805	
11806	/** returns all bilinear terms that are contained in all nonlinear constraints
11807	 *
11808	 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11809	 * @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.
11810	 */
11811	SCIP_CONSNONLINEAR_BILINTERM* SCIPgetBilinTermsNonlinear(
11812	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11813	   )
11814	{
11815	   SCIP_CONSHDLRDATA* conshdlrdata;
11816	
11817	   assert(conshdlr != NULL);
11818	
11819	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11820	   assert(conshdlrdata != NULL);
11821	
11822	   return conshdlrdata->bilinterms;
11823	}
11824	
11825	/** returns the index of the bilinear term representing the product of the two given variables
11826	 *
11827	 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11828	 * @return The method returns -1 if the variables do not appear bilinearly.
11829	 */
11830	int SCIPgetBilinTermIdxNonlinear(
11831	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
11832	   SCIP_VAR*             x,                  /**< first variable */
11833	   SCIP_VAR*             y                   /**< second variable */
11834	   )
11835	{
11836	   SCIP_CONSHDLRDATA* conshdlrdata;
11837	   SCIP_CONSNONLINEAR_BILINTERM entry;
11838	   int idx;
11839	
11840	   assert(conshdlr != NULL);
11841	   assert(x != NULL);
11842	   assert(y != NULL);
11843	
11844	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11845	   assert(conshdlrdata != NULL);
11846	
11847	   if( conshdlrdata->bilinhashtable == NULL )
11848	   {
11849	      return -1;
11850	   }
11851	
11852	   /* ensure that x.index <= y.index */
11853	   if( SCIPvarCompare(x, y) == 1 )
11854	   {
11855	      SCIPswapPointers((void**)&x, (void**)&y);
11856	   }
11857	   assert(SCIPvarCompare(x, y) < 1);
11858	
11859	   /* use a new entry to find the image in the bilinear hash table */
11860	   entry.x = x;
11861	   entry.y = y;
11862	   idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
11863	   assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11864	   assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
11865	   assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
11866	
11867	   return idx;
11868	}
11869	
11870	/** returns the bilinear term that represents the product of two given variables
11871	 *
11872	 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11873	 * @return The method returns NULL if the variables do not appear bilinearly.
11874	 */
11875	SCIP_CONSNONLINEAR_BILINTERM* SCIPgetBilinTermNonlinear(
11876	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
11877	   SCIP_VAR*             x,                  /**< first variable */
11878	   SCIP_VAR*             y                   /**< second variable */
11879	   )
11880	{
11881	   SCIP_CONSHDLRDATA* conshdlrdata;
11882	   int idx;
11883	
11884	   assert(conshdlr != NULL);
11885	   assert(x != NULL);
11886	   assert(y != NULL);
11887	
11888	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11889	   assert(conshdlrdata != NULL);
11890	
11891	   idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
11892	   assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11893	
11894	   if( idx >= 0 )
11895	   {
11896	      return &conshdlrdata->bilinterms[idx];
11897	   }
11898	
11899	   return NULL;
11900	}
11901	
11902	/** evaluates an auxiliary expression for a bilinear term */
11903	SCIP_Real SCIPevalBilinAuxExprNonlinear(
11904	   SCIP*                 scip,               /**< SCIP data structure */
11905	   SCIP_VAR*             x,                  /**< first variable of the bilinear term */
11906	   SCIP_VAR*             y,                  /**< second variable of the bilinear term */
11907	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr,      /**< auxiliary expression */
11908	   SCIP_SOL*             sol                 /**< solution at which to evaluate (can be NULL) */
11909	   )
11910	{
11911	   assert(scip != NULL);
11912	   assert(x != NULL);
11913	   assert(y != NULL);
11914	   assert(auxexpr != NULL);
11915	   assert(auxexpr->auxvar != NULL);
11916	
11917	   return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
11918	          auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
11919	}
11920	
11921	/** stores the variables of a bilinear term in the data of the constraint handler */
11922	SCIP_RETCODE SCIPinsertBilinearTermExistingNonlinear(
11923	   SCIP*                 scip,               /**< SCIP data structure */
11924	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
11925	   SCIP_VAR*             x,                  /**< first variable */
11926	   SCIP_VAR*             y,                  /**< second variable */
11927	   SCIP_VAR*             auxvar,             /**< auxiliary variable (might be NULL) */
11928	   int                   nlockspos,          /**< number of positive expression locks */
11929	   int                   nlocksneg           /**< number of negative expression locks */
11930	   )
11931	{
11932	   SCIP_CONSHDLRDATA* conshdlrdata;
11933	   SCIP_CONSNONLINEAR_BILINTERM* term;
11934	   int idx;
11935	
11936	   assert(conshdlr != NULL);
11937	
11938	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11939	   assert(conshdlrdata != NULL);
11940	
11941	   SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
11942	
11943	   term = &conshdlrdata->bilinterms[idx];
11944	   assert(term != NULL);
11945	   assert(term->nauxexprs == 0);  /* existing terms should be added before implicit terms */
11946	   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) */
11947	
11948	   /* store and capture auxiliary variable */
11949	   if( auxvar != NULL )
11950	   {
11951	      term->aux.var = auxvar;
11952	      SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
11953	   }
11954	
11955	   return SCIP_OKAY;
11956	}
11957	
11958	/** stores the variables of a bilinear term in the data of the constraint handler */
11959	SCIP_RETCODE SCIPinsertBilinearTermImplicitNonlinear(
11960	   SCIP*                 scip,               /**< SCIP data structure */
11961	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
11962	   SCIP_VAR*             x,                  /**< first variable */
11963	   SCIP_VAR*             y,                  /**< second variable */
11964	   SCIP_VAR*             auxvar,             /**< auxiliary variable (might be NULL) */
11965	   SCIP_Real             coefx,              /**< coefficient of x in the auxiliary expression */
11966	   SCIP_Real             coefy,              /**< coefficient of y in the auxiliary expression */
11967	   SCIP_Real             coefaux,            /**< coefficient of auxvar in the auxiliary expression */
11968	   SCIP_Real             cst,                /**< constant of the auxiliary expression */
11969	   SCIP_Bool             overestimate        /**< whether the auxiliary expression overestimates the bilinear product */
11970	   )
11971	{
11972	   SCIP_CONSHDLRDATA* conshdlrdata;
11973	   SCIP_CONSNONLINEAR_BILINTERM* term;
11974	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr;
11975	   int idx;
11976	   int nlockspos;
11977	   int nlocksneg;
11978	   SCIP_Bool added;
11979	
11980	   assert(conshdlr != NULL);
11981	
11982	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11983	   assert(conshdlrdata != NULL);
11984	
11985	   nlockspos = overestimate ? 1 : 0;
11986	   nlocksneg = overestimate ? 0 : 1;
11987	
11988	   SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
11989	
11990	   term = &conshdlrdata->bilinterms[idx];
11991	   assert(term != NULL);
11992	   assert(SCIPvarCompare(term->x, term->y) < 1);
11993	
11994	   if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
11995	   {
11996	      SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
11997	      /* this is the case where we are adding an implicitly defined relation for a product that has already
11998	       * been explicitly defined; convert auxvar into an auxexpr */
11999	
12000	      /* nothing to do if we aren't allowed to add more than one auxexpr per term */
12001	      if( conshdlrdata->bilinmaxnauxexprs <= 1 )
12002	         return SCIP_OKAY;
12003	
12004	      SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
12005	      auxvarexpr->cst = 0.0;
12006	      auxvarexpr->coefs[0] = 1.0;
12007	      auxvarexpr->coefs[1] = 0.0;
12008	      auxvarexpr->coefs[2] = 0.0;
12009	      auxvarexpr->auxvar = term->aux.var;
12010	      auxvarexpr->underestimate = term->nlocksneg > 0;
12011	      auxvarexpr->overestimate = term->nlockspos > 0;
12012	
12013	      /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
12014	      term->aux.exprs = NULL;
12015	
12016	      SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
12017	
12018	      /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
12019	      assert(added);
12020	   }
12021	
12022	   /* create and add auxexpr */
12023	   SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
12024	   auxexpr->underestimate = !overestimate;
12025	   auxexpr->overestimate = overestimate;
12026	   auxexpr->auxvar = auxvar;
12027	   auxexpr->coefs[0] = coefaux;
12028	   if( term->x == x )
12029	   {
12030	      assert(term->y == y);
12031	      auxexpr->coefs[1] = coefx;
12032	      auxexpr->coefs[2] = coefy;
12033	   }
12034	   else
12035	   {
12036	      assert(term->x == y);
12037	      assert(term->y == x);
12038	      auxexpr->coefs[1] = coefy;
12039	      auxexpr->coefs[2] = coefx;
12040	   }
12041	   auxexpr->cst = cst;
12042	   SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
12043	
12044	   if( !added )
12045	   {
12046	      SCIPfreeBlockMemory(scip, &auxexpr);
12047	   }
12048	   else if( auxvar != NULL )
12049	   { /* capture auxiliary variable */
12050	      SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
12051	   }
12052	
12053	   return SCIP_OKAY;
12054	}
12055	
12056	/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
12057	SCIP_RETCODE SCIPcomputeFacetVertexPolyhedralNonlinear(
12058	   SCIP*                 scip,               /**< SCIP data structure */
12059	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
12060	   SCIP_Bool             overestimate,       /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
12061	   SCIP_DECL_VERTEXPOLYFUN((*function)),     /**< pointer to vertex polyhedral function */
12062	   void*                 fundata,            /**< data for function evaluation (can be NULL) */
12063	   SCIP_Real*            xstar,              /**< point to be separated */
12064	   SCIP_Real*            box,                /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
12065	   int                   nallvars,           /**< half of the length of box */
12066	   SCIP_Real             targetvalue,        /**< target value: no need to compute facet if value in xstar would be worse than this value */
12067	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
12068	   SCIP_Real*            facetcoefs,         /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
12069	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
12070	   )
12071	{
12072	   SCIP_Real* corner;
12073	   SCIP_Real* funvals;
12074	   int* nonfixedpos;
12075	   SCIP_Real maxfaceterror;
12076	   int nvars; /* number of nonfixed variables */
12077	   unsigned int ncorners;
12078	   unsigned int i;
12079	   int j;
12080	
12081	   assert(scip != NULL);
12082	   assert(conshdlr != NULL);
12083	   assert(function != NULL);
12084	   assert(xstar != NULL);
12085	   assert(box != NULL);
12086	   assert(success != NULL);
12087	   assert(facetcoefs != NULL);
12088	   assert(facetconstant != NULL);
12089	
12090	   *success = FALSE;
12091	
12092	   /* identify fixed variables */
12093	   SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
12094	   nvars = 0;
12095	   for( j = 0; j < nallvars; ++j )
12096	   {
12097	      if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12098	         continue;
12099	      nonfixedpos[nvars] = j;
12100	      nvars++;
12101	   }
12102	
12103	   /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
12104	    * if too many variables are not fixed, then we do nothing currently
12105	    */
12106	   if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
12107	   {
12108	      SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
12109	      SCIPfreeBufferArray(scip, &nonfixedpos);
12110	      return SCIP_OKAY;
12111	   }
12112	
12113	   /* compute f(v^i) for each corner v^i of [l,u] */
12114	   ncorners = POWEROFTWO(nvars);
12115	   SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
12116	   SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
12117	   for( j = 0; j < nallvars; ++j )
12118	   {
12119	      if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12120	         corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
12121	   }
12122	   for( i = 0; i < ncorners; ++i )
12123	   {
12124	      SCIPdebugMsg(scip, "corner %u: ", i);
12125	      for( j = 0; j < nvars; ++j )
12126	      {
12127	         int varpos = nonfixedpos[j];
12128	         /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
12129	          * we check this by shifting i for j positions to the right and checking whether the last bit is set
12130	          */
12131	         if( (i >> j) & 0x1 )
12132	            corner[varpos] = box[2 * varpos + 1]; /* ub of var */
12133	         else
12134	            corner[varpos] = box[2 * varpos ]; /* lb of var */
12135	         SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
12136	         assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
12137	      }
12138	
12139	      funvals[i] = function(corner, nallvars, fundata);
12140	
12141	      SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
12142	
12143	      if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
12144	      {
12145	         SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
12146	         goto CLEANUP;
12147	      }
12148	   }
12149	
12150	   /* clear coefs array; below we only fill in coefs for nonfixed variables */
12151	   BMSclearMemoryArray(facetcoefs, nallvars);
12152	
12153	   if( nvars == 1 )
12154	   {
12155	      SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
12156	
12157	      /* check whether target has been missed */
12158	      if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
12159	      {
12160	         SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
12161	         *success = FALSE;
12162	      }
12163	   }
12164	   else if( nvars == 2 )
12165	   {
12166	      int idx1 = nonfixedpos[0];
12167	      int idx2 = nonfixedpos[1];
12168	      SCIP_Real p1[2] = { box[2*idx1],   box[2*idx2]   }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
12169	      SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2]   }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
12170	      SCIP_Real p3[2] = { box[2*idx1],   box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
12171	      SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
12172	      SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
12173	      SCIP_Real coefs[2] = { 0.0, 0.0 };
12174	
12175	      SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
12176	
12177	      facetcoefs[idx1] = coefs[0];
12178	      facetcoefs[idx2] = coefs[1];
12179	   }
12180	   else
12181	   {
12182	      SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
12183	   }
12184	   if( !*success )
12185	   {
12186	      SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
12187	      goto CLEANUP;
12188	   }
12189	
12190	   /*
12191	    *  check and adjust facet with the algorithm of Rikun et al.
12192	    */
12193	
12194	   maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
12195	
12196	   /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
12197	   if( maxfaceterror > 0.0 )
12198	   {
12199	      SCIP_CONSHDLRDATA* conshdlrdata;
12200	      SCIP_Real midval;
12201	      SCIP_Real feastol;
12202	
12203	      feastol = SCIPgetStage(scip) == SCIP_STAGE_SOLVING ? SCIPgetLPFeastol(scip) : SCIPfeastol(scip);
12204	
12205	      /* evaluate function in middle point to get some idea for a scaling */
12206	      for( j = 0; j < nvars; ++j )
12207	         corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
12208	      midval = function(corner, nallvars, fundata);
12209	      if( midval == SCIP_INVALID )
12210	         midval = 1.0;
12211	
12212	      conshdlrdata = SCIPconshdlrGetData(conshdlr);
12213	      assert(conshdlrdata != NULL);
12214	
12215	      /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
12216	      if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
12217	      {
12218	         SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
12219	         *success = FALSE;
12220	         goto CLEANUP;
12221	      }
12222	
12223	      SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
12224	
12225	      if( overestimate )
12226	         *facetconstant += maxfaceterror;
12227	      else
12228	         *facetconstant -= maxfaceterror;
12229	   }
12230	
12231	   /* if we made it until here, then we have a nice facet */
12232	   assert(*success);
12233	
12234	CLEANUP:
12235	   /* free allocated memory */
12236	   SCIPfreeBufferArray(scip, &corner);
12237	   SCIPfreeBufferArray(scip, &funvals);
12238	   SCIPfreeBufferArray(scip, &nonfixedpos);
12239	
12240	   return SCIP_OKAY;
12241	}
12242	
12243	/*
12244	 * constraint specific interface methods
12245	 */
12246	
12247	/** returns the expression of the given nonlinear constraint */
12248	SCIP_EXPR* SCIPgetExprNonlinear(
12249	   SCIP_CONS*            cons                /**< constraint data */
12250	   )
12251	{
12252	   SCIP_CONSDATA* consdata;
12253	
12254	   assert(cons != NULL);
12255	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12256	
12257	   consdata = SCIPconsGetData(cons);
12258	   assert(consdata != NULL);
12259	
12260	   return consdata->expr;
12261	}
12262	
12263	/** gets the left hand side of a nonlinear constraint */
12264	SCIP_Real SCIPgetLhsNonlinear(
12265	   SCIP_CONS*            cons                /**< constraint data */
12266	   )
12267	{
12268	   SCIP_CONSDATA* consdata;
12269	
12270	   assert(cons != NULL);
12271	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12272	
12273	   consdata = SCIPconsGetData(cons);
12274	   assert(consdata != NULL);
12275	
12276	   return consdata->lhs;
12277	}
12278	
12279	/** gets the right hand side of a nonlinear constraint */
12280	SCIP_Real SCIPgetRhsNonlinear(
12281	   SCIP_CONS*            cons                /**< constraint data */
12282	   )
12283	{
12284	   SCIP_CONSDATA* consdata;
12285	
12286	   assert(cons != NULL);
12287	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12288	
12289	   consdata = SCIPconsGetData(cons);
12290	   assert(consdata != NULL);
12291	
12292	   return consdata->rhs;
12293	}
12294	
12295	/** gets the nonlinear constraint as a nonlinear row representation. */
12296	SCIP_RETCODE SCIPgetNlRowNonlinear(
12297	   SCIP*                 scip,               /**< SCIP data structure */
12298	   SCIP_CONS*            cons,               /**< constraint */
12299	   SCIP_NLROW**          nlrow               /**< pointer to store nonlinear row */
12300	   )
12301	{
12302	   SCIP_CONSDATA* consdata;
12303	
12304	   assert(cons  != NULL);
12305	   assert(nlrow != NULL);
12306	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12307	
12308	   consdata = SCIPconsGetData(cons);
12309	   assert(consdata != NULL);
12310	
12311	   if( consdata->nlrow == NULL )
12312	   {
12313	      SCIP_CALL( createNlRow(scip, cons) );
12314	   }
12315	   assert(consdata->nlrow != NULL);
12316	   *nlrow = consdata->nlrow;
12317	
12318	   return SCIP_OKAY;
12319	}
12320	
12321	/** returns the curvature of the expression of a given nonlinear constraint
12322	 *
12323	 * @note The curvature information is computed during CONSINITSOL.
12324	 */
12325	SCIP_EXPRCURV SCIPgetCurvatureNonlinear(
12326	   SCIP_CONS*            cons                /**< constraint data */
12327	   )
12328	{
12329	   SCIP_CONSDATA* consdata;
12330	
12331	   assert(cons != NULL);
12332	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12333	
12334	   consdata = SCIPconsGetData(cons);
12335	   assert(consdata != NULL);
12336	
12337	   return consdata->curv;
12338	}
12339	
12340	/** checks whether expression of constraint can be represented as quadratic form
12341	 *
12342	 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
12343	 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
12344	 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
12345	 */
12346	SCIP_RETCODE SCIPcheckQuadraticNonlinear(
12347	   SCIP*                 scip,               /**< SCIP data structure */
12348	   SCIP_CONS*            cons,               /**< constraint data */
12349	   SCIP_Bool*            isquadratic         /**< buffer to store whether constraint is quadratic */
12350	   )
12351	{
12352	   SCIP_CONSDATA* consdata;
12353	
12354	   assert(scip != NULL);
12355	   assert(cons != NULL);
12356	   assert(isquadratic != NULL);
12357	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12358	
12359	   consdata = SCIPconsGetData(cons);
12360	   assert(consdata != NULL);
12361	   assert(consdata->expr != NULL);
12362	
12363	   /* check whether constraint expression is quadratic in extended formulation */
12364	   SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
12365	
12366	   /* if not quadratic in non-extended formulation, then do indicate quadratic */
12367	   if( *isquadratic )
12368	      *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
12369	
12370	   return SCIP_OKAY;
12371	}
12372	
12373	/** changes left-hand-side of a nonlinear constraint
12374	 *
12375	 * @attention This method can only be called in the problem stage.
12376	 */
12377	SCIP_RETCODE SCIPchgLhsNonlinear(
12378	   SCIP*                 scip,               /**< SCIP data structure */
12379	   SCIP_CONS*            cons,               /**< constraint data */
12380	   SCIP_Real             lhs                 /**< new left-hand-side */
12381	   )
12382	{
12383	   SCIP_CONSDATA* consdata;
12384	
12385	   assert(scip != NULL);
12386	   assert(cons != NULL);
12387	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12388	
12389	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12390	   {
12391	      SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12392	      return SCIP_INVALIDCALL;
12393	   }
12394	
12395	   /* we should have an original constraint */
12396	   assert(SCIPconsIsOriginal(cons));
12397	
12398	   consdata = SCIPconsGetData(cons);
12399	   assert(consdata != NULL);
12400	
12401	   if( consdata->lhs == lhs )
12402	      return SCIP_OKAY;
12403	
12404	   consdata->lhs = lhs;
12405	
12406	   /* not sure we care about any of these flags for original constraints */
12407	   consdata->ispropagated = FALSE;
12408	
12409	   return SCIP_OKAY;
12410	}
12411	
12412	/** changes right-hand-side of a nonlinear constraint
12413	 *
12414	 * @attention This method can only be called in the problem stage.
12415	 */
12416	SCIP_RETCODE SCIPchgRhsNonlinear(
12417	   SCIP*                 scip,               /**< SCIP data structure */
12418	   SCIP_CONS*            cons,               /**< constraint data */
12419	   SCIP_Real             rhs                 /**< new right-hand-side */
12420	   )
12421	{
12422	   SCIP_CONSDATA* consdata;
12423	
12424	   assert(scip != NULL);
12425	   assert(cons != NULL);
12426	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12427	
12428	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12429	   {
12430	      SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12431	      return SCIP_INVALIDCALL;
12432	   }
12433	
12434	   /* we should have an original constraint */
12435	   assert(SCIPconsIsOriginal(cons));
12436	
12437	   consdata = SCIPconsGetData(cons);
12438	   assert(consdata != NULL);
12439	
12440	   if( consdata->rhs == rhs )
12441	      return SCIP_OKAY;
12442	
12443	   consdata->rhs = rhs;
12444	
12445	   /* not sure we care about any of these flags for original constraints */
12446	   consdata->ispropagated = FALSE;
12447	
12448	   return SCIP_OKAY;
12449	}
12450	
12451	/** changes expression of a nonlinear constraint
12452	 *
12453	 * @attention This method can only be called in the problem stage.
12454	 */
12455	SCIP_RETCODE SCIPchgExprNonlinear(
12456	   SCIP*                 scip,               /**< SCIP data structure */
12457	   SCIP_CONS*            cons,               /**< constraint data */
12458	   SCIP_EXPR*            expr                /**< new expression */
12459	   )
12460	{
12461	   SCIP_CONSHDLR* conshdlr;
12462	   SCIP_CONSDATA* consdata;
12463	
12464	   assert(scip != NULL);
12465	   assert(cons != NULL);
12466	   assert(expr != NULL);
12467	
12468	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12469	   {
12470	      SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
12471	      return SCIP_INVALIDCALL;
12472	   }
12473	
12474	   /* we should have an original constraint */
12475	   assert(SCIPconsIsOriginal(cons));
12476	
12477	   conshdlr = SCIPconsGetHdlr(cons);
12478	   assert(conshdlr != NULL);
12479	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12480	
12481	   consdata = SCIPconsGetData(cons);
12482	   assert(consdata != NULL);
12483	   assert(consdata->expr != NULL);
12484	
12485	   /* we should not have collected additional data for the expr
12486	    * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12487	    */
12488	   assert(consdata->nvarexprs == 0);
12489	   assert(consdata->varexprs == NULL);
12490	   assert(!consdata->catchedevents);
12491	
12492	   SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
12493	
12494	   /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12495	   SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12496	
12497	   /* not sure we care about any of these flags for original constraints */
12498	   consdata->curv = SCIP_EXPRCURV_UNKNOWN;
12499	   consdata->issimplified = FALSE;
12500	   consdata->ispropagated = FALSE;
12501	
12502	   return SCIP_OKAY;
12503	}
12504	
12505	/** adds coef * var to nonlinear constraint
12506	 *
12507	 * @attention This method can only be called in the problem stage.
12508	 */
12509	SCIP_RETCODE SCIPaddLinearVarNonlinear(
12510	   SCIP*                 scip,               /**< SCIP data structure */
12511	   SCIP_CONS*            cons,               /**< constraint data */
12512	   SCIP_VAR*             var,                /**< variable */
12513	   SCIP_Real             coef                /**< coefficient */
12514	   )
12515	{
12516	   SCIP_CONSHDLR* conshdlr;
12517	   SCIP_CONSDATA* consdata;
12518	   SCIP_EXPR* varexpr;
12519	
12520	   assert(scip != NULL);
12521	   assert(cons != NULL);
12522	
12523	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12524	   {
12525	      SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12526	      return SCIP_INVALIDCALL;
12527	   }
12528	
12529	   /* we should have an original constraint */
12530	   assert(SCIPconsIsOriginal(cons));
12531	
12532	   if( coef == 0.0 )
12533	      return SCIP_OKAY;
12534	
12535	   conshdlr = SCIPconsGetHdlr(cons);
12536	   assert(conshdlr != NULL);
12537	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12538	
12539	   consdata = SCIPconsGetData(cons);
12540	   assert(consdata != NULL);
12541	   assert(consdata->expr != NULL);
12542	
12543	   /* we should not have collected additional data for it
12544	    * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12545	    */
12546	   assert(consdata->nvarexprs == 0);
12547	   assert(consdata->varexprs == NULL);
12548	   assert(!consdata->catchedevents);
12549	
12550	   SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
12551	
12552	   /* append to sum, if consdata->expr is sum and not used anywhere else */
12553	   if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12554	   {
12555	      SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
12556	   }
12557	   else
12558	   {
12559	      /* create new expression = 1 * consdata->expr + coef * var */
12560	      SCIP_EXPR* children[2] = { consdata->expr, varexpr };
12561	      SCIP_Real coefs[2] = { 1.0, coef };
12562	
12563	      SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12564	
12565	      /* release old root expr */
12566	      SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12567	   }
12568	
12569	   SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12570	
12571	   /* not sure we care about any of these flags for original constraints */
12572	   consdata->issimplified = FALSE;
12573	   consdata->ispropagated = FALSE;
12574	
12575	   return SCIP_OKAY;
12576	}
12577	
12578	/** adds coef * expr to nonlinear constraint
12579	 *
12580	 * @attention This method can only be called in the problem stage.
12581	 */
12582	SCIP_RETCODE SCIPaddExprNonlinear(
12583	   SCIP*                 scip,               /**< SCIP data structure */
12584	   SCIP_CONS*            cons,               /**< nonlinear constraint */
12585	   SCIP_EXPR*            expr,               /**< expression */
12586	   SCIP_Real             coef                /**< coefficient */
12587	   )
12588	{
12589	   SCIP_CONSHDLR* conshdlr;
12590	   SCIP_CONSDATA* consdata;
12591	   SCIP_EXPR* exprowned;
12592	
12593	   assert(scip != NULL);
12594	   assert(cons != NULL);
12595	
12596	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12597	   {
12598	      SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12599	      return SCIP_INVALIDCALL;
12600	   }
12601	
12602	   /* we should have an original constraint */
12603	   assert(SCIPconsIsOriginal(cons));
12604	
12605	   if( coef == 0.0 )
12606	      return SCIP_OKAY;
12607	
12608	   conshdlr = SCIPconsGetHdlr(cons);
12609	   assert(conshdlr != NULL);
12610	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12611	
12612	   consdata = SCIPconsGetData(cons);
12613	   assert(consdata != NULL);
12614	   assert(consdata->expr != NULL);
12615	
12616	   /* we should not have collected additional data for it
12617	    * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12618	    */
12619	   assert(consdata->nvarexprs == 0);
12620	   assert(consdata->varexprs == NULL);
12621	   assert(!consdata->catchedevents);
12622	
12623	   /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12624	   SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12625	
12626	   /* append to sum, if consdata->expr is sum and not used anywhere else */
12627	   if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12628	   {
12629	      SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
12630	   }
12631	   else
12632	   {
12633	      /* create new expression = 1 * consdata->expr + coef * var */
12634	      SCIP_EXPR* children[2] = { consdata->expr, exprowned };
12635	      SCIP_Real coefs[2] = { 1.0, coef };
12636	
12637	      SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12638	
12639	      /* release old root expr */
12640	      SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12641	   }
12642	
12643	   SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
12644	
12645	   /* not sure we care about any of these flags for original constraints */
12646	   consdata->issimplified = FALSE;
12647	   consdata->ispropagated = FALSE;
12648	
12649	   return SCIP_OKAY;
12650	}
12651	
12652	/** gets absolute violation of nonlinear constraint
12653	 *
12654	 * This function evaluates the constraints in the given solution.
12655	 *
12656	 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
12657	 */
12658	SCIP_RETCODE SCIPgetAbsViolationNonlinear(
12659	   SCIP*                 scip,               /**< SCIP data structure */
12660	   SCIP_CONS*            cons,               /**< constraint */
12661	   SCIP_SOL*             sol,                /**< solution to check */
12662	   SCIP_Real*            viol                /**< buffer to store computed violation */
12663	   )
12664	{
12665	   assert(cons != NULL);
12666	   assert(viol != NULL);
12667	
12668	   SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12669	   *viol = getConsAbsViolation(cons);
12670	
12671	   return SCIP_OKAY;
12672	}
12673	
12674	/** gets scaled violation of nonlinear constraint
12675	 *
12676	 * This function evaluates the constraints in the given solution.
12677	 *
12678	 * The scaling that is applied to the absolute violation of the constraint
12679	 * depends on the setting of parameter constraints/nonlinear/violscale.
12680	 */
12681	SCIP_RETCODE SCIPgetRelViolationNonlinear(
12682	   SCIP*                 scip,               /**< SCIP data structure */
12683	   SCIP_CONS*            cons,               /**< constraint */
12684	   SCIP_SOL*             sol,                /**< solution to check */
12685	   SCIP_Real*            viol                /**< buffer to store computed violation */
12686	   )
12687	{
12688	   assert(cons != NULL);
12689	   assert(viol != NULL);
12690	
12691	   SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12692	   SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
12693	
12694	   return SCIP_OKAY;
12695	}
12696	
12697	/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
12698	void SCIPgetLinvarMayDecreaseNonlinear(
12699	   SCIP*                 scip,               /**< SCIP data structure */
12700	   SCIP_CONS*            cons,               /**< nonlinear constraint */
12701	   SCIP_VAR**            var,                /**< pointer to store the variable */
12702	   SCIP_Real*            coef                /**< pointer to store the coefficient */
12703	   )
12704	{
12705	   SCIP_CONSDATA* consdata;
12706	
12707	   assert(cons != NULL);
12708	   assert(var != NULL);
12709	   assert(coef != NULL);
12710	
12711	   /* check for a linear variable that can be increased or decreased without harming feasibility */
12712	   findUnlockedLinearVar(scip, cons);
12713	
12714	   consdata = SCIPconsGetData(cons);
12715	   assert(consdata != NULL);
12716	
12717	   *var = consdata->linvardecr;
12718	   *coef = consdata->linvardecrcoef;
12719	}
12720	
12721	/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
12722	void SCIPgetLinvarMayIncreaseNonlinear(
12723	   SCIP*                 scip,               /**< SCIP data structure */
12724	   SCIP_CONS*            cons,               /**< nonlinear constraint */
12725	   SCIP_VAR**            var,                /**< pointer to store the variable */
12726	   SCIP_Real*            coef                /**< pointer to store the coefficient */
12727	   )
12728	{
12729	   SCIP_CONSDATA* consdata;
12730	
12731	   assert(cons != NULL);
12732	   assert(var != NULL);
12733	   assert(coef != NULL);
12734	
12735	   /* check for a linear variable that can be increased or decreased without harming feasibility */
12736	   findUnlockedLinearVar(scip, cons);
12737	
12738	   consdata = SCIPconsGetData(cons);
12739	   assert(consdata != NULL);
12740	
12741	   *var = consdata->linvarincr;
12742	   *coef = consdata->linvarincrcoef;
12743	}
12744	
12745	
12746	/*
12747	 * Methods for Expressions in Nonlinear Constraints
12748	 */
12749	
12750	/** returns the number of positive rounding locks of an expression */
12751	int SCIPgetExprNLocksPosNonlinear(
12752	   SCIP_EXPR*            expr                /**< expression */
12753	   )
12754	{
12755	   assert(expr != NULL);
12756	   assert(SCIPexprGetOwnerData(expr) != NULL);
12757	
12758	   return SCIPexprGetOwnerData(expr)->nlockspos;
12759	}
12760	
12761	/** returns the number of negative rounding locks of an expression */
12762	int SCIPgetExprNLocksNegNonlinear(
12763	   SCIP_EXPR*            expr                /**< expression */
12764	   )
12765	{
12766	   assert(expr != NULL);
12767	   assert(SCIPexprGetOwnerData(expr) != NULL);
12768	
12769	   return SCIPexprGetOwnerData(expr)->nlocksneg;
12770	}
12771	
12772	/** returns the variable used for linearizing a given expression (return value might be NULL)
12773	 *
12774	 * @note for variable expression it returns the corresponding variable
12775	 */
12776	SCIP_VAR* SCIPgetExprAuxVarNonlinear(
12777	   SCIP_EXPR*            expr                /**< expression */
12778	   )
12779	{
12780	   SCIP_EXPR_OWNERDATA* ownerdata;
12781	
12782	   assert(expr != NULL);
12783	
12784	   ownerdata = SCIPexprGetOwnerData(expr);
12785	   assert(ownerdata != NULL);
12786	
12787	   return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
12788	}
12789	
12790	/** returns the number of enforcements for an expression */
12791	int SCIPgetExprNEnfosNonlinear(
12792	   SCIP_EXPR*            expr                /**< expression */
12793	   )
12794	{
12795	   assert(expr != NULL);
12796	   assert(SCIPexprGetOwnerData(expr) != NULL);
12797	
12798	   return SCIPexprGetOwnerData(expr)->nenfos;
12799	}
12800	
12801	/** returns the data for one of the enforcements of an expression */
12802	void SCIPgetExprEnfoDataNonlinear(
12803	   SCIP_EXPR*            expr,               /**< expression */
12804	   int                   idx,                /**< position of enforcement in enfos array */
12805	   SCIP_NLHDLR**         nlhdlr,             /**< buffer to store nlhldr */
12806	   SCIP_NLHDLREXPRDATA** nlhdlrexprdata,     /**< buffer to store nlhdlr data for expression, or NULL */
12807	   SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
12808	   SCIP_Bool*            sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
12809	   SCIP_Bool*            sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
12810	   SCIP_Real*            auxvalue            /**< buffer to store current auxvalue, or NULL */
12811	   )
12812	{
12813	   SCIP_EXPR_OWNERDATA* ownerdata;
12814	
12815	   assert(expr != NULL);
12816	
12817	   ownerdata = SCIPexprGetOwnerData(expr);
12818	   assert(ownerdata != NULL);
12819	   assert(idx >= 0);
12820	   assert(idx < ownerdata->nenfos);
12821	   assert(ownerdata->enfos[idx] != NULL);
12822	   assert(nlhdlr != NULL);
12823	
12824	   *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
12825	
12826	   if( nlhdlrexprdata != NULL )
12827	      *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
12828	
12829	   if( nlhdlrparticipation != NULL )
12830	      *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
12831	
12832	   if( sepabelowusesactivity != NULL )
12833	      *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
12834	
12835	   if( sepaaboveusesactivity != NULL )
12836	      *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
12837	
12838	   if( auxvalue != NULL )
12839	      *auxvalue = ownerdata->enfos[idx]->auxvalue;
12840	}
12841	
12842	/** sets the auxiliary value of expression for one of the enforcements of an expression */
12843	void SCIPsetExprEnfoAuxValueNonlinear(
12844	   SCIP_EXPR*            expr,               /**< expression */
12845	   int                   idx,                /**< position of enforcement in enfos array */
12846	   SCIP_Real             auxvalue            /**< the new value of auxval */
12847	   )
12848	{
12849	   SCIP_EXPR_OWNERDATA* ownerdata;
12850	
12851	   assert(expr != NULL);
12852	
12853	   ownerdata = SCIPexprGetOwnerData(expr);
12854	   assert(ownerdata != NULL);
12855	
12856	   assert(idx >= 0);
12857	   assert(idx < ownerdata->nenfos);
12858	   assert(ownerdata->enfos[idx] != NULL);
12859	
12860	   ownerdata->enfos[idx]->auxvalue = auxvalue;
12861	}
12862	
12863	/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
12864	 *
12865	 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12866	 */
12867	unsigned int SCIPgetExprNPropUsesActivityNonlinear(
12868	   SCIP_EXPR*            expr                /**< expression */
12869	   )
12870	{
12871	   assert(expr != NULL);
12872	   assert(SCIPexprGetOwnerData(expr) != NULL);
12873	
12874	   return SCIPexprGetOwnerData(expr)->nactivityusesprop;
12875	}
12876	
12877	/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
12878	 *
12879	 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12880	 */
12881	unsigned int SCIPgetExprNSepaUsesActivityNonlinear(
12882	   SCIP_EXPR*            expr                /**< expression */
12883	   )
12884	{
12885	   assert(expr != NULL);
12886	   assert(SCIPexprGetOwnerData(expr) != NULL);
12887	
12888	   return SCIPexprGetOwnerData(expr)->nactivityusessepa;
12889	}
12890	
12891	/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
12892	 *
12893	 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12894	 */
12895	unsigned int SCIPgetExprNAuxvarUsesNonlinear(
12896	   SCIP_EXPR*            expr                /**< expression */
12897	   )
12898	{
12899	   assert(expr != NULL);
12900	   assert(SCIPexprGetOwnerData(expr) != NULL);
12901	
12902	   return SCIPexprGetOwnerData(expr)->nauxvaruses;
12903	}
12904	
12905	/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
12906	 *
12907	 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
12908	 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
12909	 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
12910	 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
12911	 *   and also increments this count for all variables in the expression.
12912	 *
12913	 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
12914	 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
12915	 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
12916	 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
12917	 */
12918	SCIP_RETCODE SCIPregisterExprUsageNonlinear(
12919	   SCIP*                 scip,               /**< SCIP data structure */
12920	   SCIP_EXPR*            expr,               /**< expression */
12921	   SCIP_Bool             useauxvar,          /**< whether an auxiliary variable will be used for estimate or cut generation */
12922	   SCIP_Bool             useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
12923	   SCIP_Bool             useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
12924	   SCIP_Bool             useactivityforsepaabove  /**< whether activity of expr will be used by overestimation */
12925	   )
12926	{
12927	   SCIP_EXPR_OWNERDATA* ownerdata;
12928	
12929	   assert(expr != NULL);
12930	
12931	   ownerdata = SCIPexprGetOwnerData(expr);
12932	   assert(ownerdata != NULL);
12933	
12934	   /* do not store auxvar request for variable expressions */
12935	   if( useauxvar && SCIPisExprVar(scip, expr) )
12936	      useauxvar = FALSE;
12937	
12938	   if( ownerdata->nenfos >= 0 &&
12939	      ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
12940	        (ownerdata->nauxvaruses == 0 && useauxvar)
12941	      ) )
12942	   {
12943	      /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
12944	       * we require additional enforcement methods, that is,
12945	       * - activity of expr was not used before but will be used now, or
12946	       * - auxiliary variable of expr was not required before but will be used now
12947	       */
12948	      SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
12949	   }
12950	
12951	   if( useauxvar )
12952	      ++ownerdata->nauxvaruses;
12953	
12954	   if( useactivityforprop )
12955	      ++ownerdata->nactivityusesprop;
12956	
12957	   if( useactivityforsepabelow || useactivityforsepaabove )
12958	      ++ownerdata->nactivityusessepa;
12959	
12960	   /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
12961	    * information is used in detectNlhdlr()
12962	    */
12963	   if( useactivityforsepabelow )
12964	      SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
12965	   if( useactivityforsepaabove )
12966	      SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
12967	
12968	   if( useactivityforprop )
12969	   {
12970	      /* if activity will be used for propagation, then make sure there is a valid activity
12971	       * this way, we can do a reversepropcall after detectNlhdlr
12972	       */
12973	      SCIP_CALL( SCIPevalExprActivity(scip, expr) );
12974	   }
12975	
12976	   /* increase the nactivityusedsepa counter for all variables used in the given expression */
12977	   if(( useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
12978	   {
12979	      SCIP_EXPRITER* it;
12980	
12981	      /* create and initialize iterator */
12982	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
12983	      SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, FALSE) );
12984	
12985	      for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
12986	         if( SCIPisExprVar(scip, expr) )
12987	            ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
12988	
12989	      /* free iterator */
12990	      SCIPfreeExpriter(&it);
12991	   }
12992	
12993	   return SCIP_OKAY;
12994	}
12995	
12996	/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
12997	 *
12998	 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
12999	 * Assume that f(x) is associated with auxiliary variable z.
13000	 *
13001	 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
13002	 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
13003	 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
13004	 *
13005	 * If necessary, f is evaluated in the given solution. If that fails (domain error),
13006	 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
13007	 */
13008	SCIP_RETCODE SCIPgetExprAbsOrigViolationNonlinear(
13009	   SCIP*                 scip,               /**< SCIP data structure */
13010	   SCIP_EXPR*            expr,               /**< expression */
13011	   SCIP_SOL*             sol,                /**< solution */
13012	   SCIP_Longint          soltag,             /**< tag of solution */
13013	   SCIP_Real*            viol,               /**< buffer to store computed violation */
13014	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(x) is violated, or NULL */
13015	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(x) is violated, or NULL */
13016	   )
13017	{
13018	   assert(scip != NULL);
13019	   assert(expr != NULL);
13020	   assert(viol != NULL);
13021	
13022	   /* make sure expression has been evaluated */
13023	   SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
13024	
13025	   /* get violation from internal method */
13026	   *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
13027	
13028	   return SCIP_OKAY;
13029	}
13030	
13031	/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
13032	 *
13033	 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13034	 * Assume that f(w) is associated with auxiliary variable z.
13035	 *
13036	 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
13037	 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
13038	 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
13039	 *
13040	 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13041	 * both `violover` and `violunder` are set to TRUE.
13042	 */
13043	SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(
13044	   SCIP*                 scip,               /**< SCIP data structure */
13045	   SCIP_EXPR*            expr,               /**< expression */
13046	   SCIP_Real             auxvalue,           /**< the value of f(w) */
13047	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
13048	   SCIP_Real*            viol,               /**< buffer to store computed violation */
13049	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(w) is violated, or NULL */
13050	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(w) is violated, or NULL */
13051	   )
13052	{
13053	   assert(scip != NULL);
13054	   assert(expr != NULL);
13055	   assert(viol != NULL);
13056	
13057	   /* get violation from internal method */
13058	   *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13059	
13060	   return SCIP_OKAY;
13061	}
13062	
13063	
13064	/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
13065	 *
13066	 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13067	 * Assume that f(w) is associated with auxiliary variable z.
13068	 *
13069	 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
13070	 * the absolute violation divided by max(1,|f(w)|).
13071	 *
13072	 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13073	 * both `violover` and `violunder` are set to TRUE.
13074	 */
13075	SCIP_RETCODE SCIPgetExprRelAuxViolationNonlinear(
13076	   SCIP*                 scip,               /**< SCIP data structure */
13077	   SCIP_EXPR*            expr,               /**< expression */
13078	   SCIP_Real             auxvalue,           /**< the value of f(w) */
13079	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
13080	   SCIP_Real*            viol,               /**< buffer to store computed violation */
13081	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(w) is violated, or NULL */
13082	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(w) is violated, or NULL */
13083	   )
13084	{
13085	   assert(scip != NULL);
13086	   assert(expr != NULL);
13087	   assert(viol != NULL);
13088	
13089	   /* get violation from internal method */
13090	   *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13091	
13092	   if( !SCIPisInfinity(scip, *viol) )
13093	   {
13094	      assert(auxvalue != SCIP_INVALID);
13095	      /* TODO maybe we should rather use max(eps,|auxvalue|)? */
13096	      *viol /= MAX(1.0, REALABS(auxvalue));
13097	   }
13098	
13099	   return SCIP_OKAY;
13100	}
13101	
13102	/** returns bounds on the expression
13103	 *
13104	 * This gives an intersection of bounds from
13105	 * - activity calculation (SCIPexprGetActivity()), if valid,
13106	 * - auxiliary variable, if present,
13107	 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
13108	 *
13109	 * @note The returned interval can be empty!
13110	 */
13111	SCIP_INTERVAL SCIPgetExprBoundsNonlinear(
13112	   SCIP*                 scip,               /**< SCIP data structure */
13113	   SCIP_EXPR*            expr                /**< expression */
13114	   )
13115	{
13116	   SCIP_EXPR_OWNERDATA* ownerdata;
13117	   SCIP_CONSHDLRDATA* conshdlrdata;
13118	   SCIP_INTERVAL bounds;
13119	
13120	   assert(scip != NULL);
13121	   assert(expr != NULL);
13122	
13123	   ownerdata = SCIPexprGetOwnerData(expr);
13124	   assert(ownerdata != NULL);
13125	
13126	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13127	   assert(conshdlrdata != NULL);
13128	
13129	   /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
13130	
13131	   /* start with propbounds if they belong to current propagation */
13132	   if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13133	   {
13134	      bounds = ownerdata->propbounds;
13135	      /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
13136	   }
13137	   else
13138	      SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &bounds);
13139	
13140	   if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
13141	   {
13142	      /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
13143	      /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
13144	      SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), bounds);
13145	   }
13146	
13147	   if( ownerdata->auxvar != NULL )
13148	   {
13149	      /* apply auxiliary variable bounds to bounds */
13150	      SCIP_INTERVAL auxvarbounds;
13151	
13152	      auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
13153	      /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
13154	      SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
13155	   }
13156	
13157	   /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
13158	
13159	   return bounds;
13160	}
13161	
13162	/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
13163	 * corresponding (auxiliary) variable (if any)
13164	 *
13165	 * @attention this function should only be called during domain propagation in cons_nonlinear
13166	 */
13167	SCIP_RETCODE SCIPtightenExprIntervalNonlinear(
13168	   SCIP*                 scip,               /**< SCIP data structure */
13169	   SCIP_EXPR*            expr,               /**< expression to be tightened */
13170	   SCIP_INTERVAL         newbounds,          /**< new bounds for the expression */
13171	   SCIP_Bool*            cutoff,             /**< buffer to store whether a cutoff was detected */
13172	   int*                  ntightenings        /**< buffer to add the total number of tightenings, or NULL */
13173	   )
13174	{
13175	   SCIP_EXPR_OWNERDATA* ownerdata;
13176	   SCIP_CONSHDLRDATA* conshdlrdata;
13177	
13178	   assert(scip != NULL);
13179	   assert(expr != NULL);
13180	   assert(cutoff != NULL);
13181	
13182	   ownerdata = SCIPexprGetOwnerData(expr);
13183	   assert(ownerdata != NULL);
13184	   assert(ownerdata->conshdlr != NULL);
13185	
13186	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13187	   assert(conshdlrdata != NULL);
13188	
13189	   /* the code below assumes that current activity is valid
13190	    * if it turns out that we cannot ensure that, then we should change code
13191	    */
13192	   assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13193	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13194	
13195	   *cutoff = FALSE;
13196	
13197	#ifdef DEBUG_PROP
13198	   SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
13199	   SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
13200	   SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
13201	#endif
13202	
13203	   if( SCIPexprIsIntegral(expr) )
13204	   {
13205	      /* apply integrality to new bounds
13206	       * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
13207	       */
13208	      if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
13209	         newbounds.inf = SCIPceil(scip, newbounds.inf);
13210	      if( newbounds.sup <  SCIP_INTERVAL_INFINITY )
13211	         newbounds.sup = SCIPfloor(scip, newbounds.sup);
13212	#ifdef DEBUG_PROP
13213	      SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
13214	#endif
13215	   }
13216	
13217	   if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newbounds) )
13218	   {
13219	      SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
13220	
13221	      *cutoff = TRUE;
13222	      return SCIP_OKAY;
13223	   }
13224	
13225	   /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
13226	   if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
13227	   {
13228	      SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
13229	
13230	      *cutoff = TRUE;
13231	      return SCIP_OKAY;
13232	   }
13233	
13234	   /* tighten newbounds w.r.t. existing expr->propbounds or activity */
13235	   if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13236	   {
13237	      /* if already having propbounds in expr, then tighten newbounds by propbounds */
13238	      SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
13239	   }
13240	   else
13241	   {
13242	      /* first time we have propbounds for expr in this propagation rounds:
13243	       * intersect with activity (though don't let it become empty if very close intervals)
13244	       */
13245	      SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
13246	   }
13247	#ifdef DEBUG_PROP
13248	   SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
13249	#endif
13250	
13251	   /* check if the new bounds lead to an empty interval */
13252	   if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newbounds) )
13253	   {
13254	      SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
13255	
13256	      *cutoff = TRUE;
13257	      return SCIP_OKAY;
13258	   }
13259	
13260	   /* if expr is not constant or variable, then store newbounds in expr->propbounds
13261	    * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
13262	    * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
13263	    */
13264	   if( SCIPexprGetNChildren(expr) > 0 )
13265	   {
13266	      ownerdata->propbounds = newbounds;
13267	      ownerdata->propboundstag = conshdlrdata->curpropboundstag;
13268	   }
13269	
13270	   /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
13271	    * propagation or update of auxvar bounds
13272	    * TODO? if we first had a considerable tightening and then only get small tightenings under the same
13273	    *   curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
13274	    *   not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
13275	    *   propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
13276	    *   one or should we not even update propbounds to newbounds if the update is small?
13277	    */
13278	   if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
13279	   {
13280	#ifdef DEBUG_PROP
13281	      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);
13282	#endif
13283	      return SCIP_OKAY;
13284	   }
13285	
13286	   if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
13287	   {
13288	      /* add expression to propagation queue if not there yet and not var or constant and
13289	       * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
13290	       */
13291	#ifdef DEBUG_PROP
13292	         SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
13293	#endif
13294	         SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
13295	         ownerdata->inpropqueue = TRUE;
13296	   }
13297	
13298	   /* update bounds on variable or auxiliary variable */
13299	   SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
13300	
13301	   return SCIP_OKAY;
13302	}
13303	
13304	/** mark constraints that include this expression to be propagated again
13305	 *
13306	 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
13307	 * a change of variable bounds, e.g., because new information on the expression is available
13308	 * that could potentially lead to tighter expression activity values.
13309	 *
13310	 * Note, that this call marks also constraints for propagation which only share some variable
13311	 * with this expression.
13312	 */
13313	SCIP_RETCODE SCIPmarkExprPropagateNonlinear(
13314	   SCIP*                 scip,               /**< SCIP data structure */
13315	   SCIP_EXPR*            expr                /**< expression to propagate again */
13316	   )
13317	{
13318	   SCIP_EXPRITER* it;
13319	   SCIP_CONSDATA* consdata;
13320	   SCIP_EXPR_OWNERDATA* ownerdata;
13321	   int c;
13322	
13323	   assert(scip != NULL);
13324	   assert(expr != NULL);
13325	
13326	   ownerdata = SCIPexprGetOwnerData(expr);
13327	   assert(ownerdata != NULL);
13328	
13329	   SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
13330	
13331	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13332	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, FALSE) );
13333	
13334	   for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13335	   {
13336	      if( !SCIPisExprVar(scip, expr) )
13337	         continue;
13338	
13339	      ownerdata = SCIPexprGetOwnerData(expr);
13340	      assert(ownerdata != NULL);
13341	
13342	      for( c = 0; c < ownerdata->nconss; ++c )
13343	      {
13344	         consdata = SCIPconsGetData(ownerdata->conss[c]);
13345	         assert(consdata != NULL);
13346	         consdata->ispropagated = FALSE;
13347	      }
13348	   }
13349	
13350	   SCIPfreeExpriter(&it);
13351	
13352	   return SCIP_OKAY;
13353	}
13354	
13355	/** adds violation-branching score to an expression
13356	 *
13357	 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
13358	 * The expression must either be a variable expression or have an aux-variable.
13359	 * In the latter case, branching on auxiliary variables must have been enabled.
13360	 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
13361	 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
13362	 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
13363	 *
13364	 * @see SCIPaddExprsViolScoreNonlinear()
13365	 */
13366	void SCIPaddExprViolScoreNonlinear(
13367	   SCIP*                 scip,               /**< SCIP data structure */
13368	   SCIP_EXPR*            expr,               /**< expression where to add branching score */
13369	   SCIP_Real             violscore           /**< violation score to add to expression */
13370	   )
13371	{
13372	   SCIP_EXPR_OWNERDATA* ownerdata;
13373	   SCIP_CONSHDLRDATA* conshdlrdata;
13374	
13375	   assert(scip != NULL);
13376	   assert(expr != NULL);
13377	   assert(violscore >= 0.0);
13378	
13379	   ownerdata = SCIPexprGetOwnerData(expr);
13380	   assert(ownerdata != NULL);
13381	
13382	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13383	   assert(conshdlrdata != NULL);
13384	
13385	   /* if not allowing to branch on auxvars, then expr must be a var-expr */
13386	   assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
13387	   /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
13388	   assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
13389	
13390	   /* reset branching score if we are in a different enfo round */
13391	   if( ownerdata->violscoretag != conshdlrdata->enforound )
13392	   {
13393	      ownerdata->violscoresum = violscore;
13394	      ownerdata->violscoremax = violscore;
13395	      ownerdata->nviolscores = 1;
13396	      ownerdata->violscoretag = conshdlrdata->enforound;
13397	      return;
13398	   }
13399	
13400	   ownerdata->violscoresum += violscore;
13401	   if( violscore > ownerdata->violscoremax )
13402	      ownerdata->violscoremax = violscore;
13403	   ++ownerdata->nviolscores;
13404	}
13405	
13406	/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
13407	 *
13408	 * Each expression must either be a variable expression or have an aux-variable.
13409	 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
13410	 * variables present in `exprs`.
13411	 */
13412	SCIP_RETCODE SCIPaddExprsViolScoreNonlinear(
13413	   SCIP*                 scip,               /**< SCIP data structure */
13414	   SCIP_EXPR**           exprs,              /**< expressions where to add branching score */
13415	   int                   nexprs,             /**< number of expressions */
13416	   SCIP_Real             violscore,          /**< violation score to add to expression */
13417	   SCIP_SOL*             sol,                /**< current solution */
13418	   SCIP_Bool*            success             /**< buffer to store whether at least one violscore was added */
13419	   )
13420	{
13421	   SCIP_EXPRITER* it;
13422	   SCIP_EXPR** varexprs;
13423	   SCIP_EXPR* e;
13424	   int nvars;
13425	   int varssize;
13426	   int i;
13427	
13428	   assert(exprs != NULL || nexprs == 0);
13429	   assert(success != NULL);
13430	
13431	   if( nexprs == 0 )
13432	   {
13433	      *success = FALSE;
13434	      return SCIP_OKAY;
13435	   }
13436	
13437	   /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
13438	   if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
13439	   {
13440	      addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
13441	      return SCIP_OKAY;
13442	   }
13443	
13444	   /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
13445	   nvars = 0;
13446	   varssize = 5;
13447	   SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
13448	
13449	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13450	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
13451	
13452	   for( i = 0; i < nexprs; ++i )
13453	   {
13454	      for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
13455	      {
13456	         assert(e != NULL);
13457	
13458	         if( SCIPisExprVar(scip, e) )
13459	         {
13460	            /* add variable expression to vars array */
13461	            if( varssize == nvars )
13462	            {
13463	               varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
13464	               SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
13465	            }
13466	            assert(varssize > nvars);
13467	
13468	            varexprs[nvars++] = e;
13469	         }
13470	      }
13471	   }
13472	
13473	   SCIPfreeExpriter(&it);
13474	
13475	   addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
13476	
13477	   SCIPfreeBufferArray(scip, &varexprs);
13478	
13479	   return SCIP_OKAY;
13480	}
13481	
13482	/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
13483	SCIP_Real SCIPgetExprViolScoreNonlinear(
13484	   SCIP_EXPR*            expr                /**< expression */
13485	   )
13486	{
13487	   SCIP_EXPR_OWNERDATA* ownerdata;
13488	   SCIP_CONSHDLRDATA* conshdlrdata;
13489	
13490	   assert(expr != NULL);
13491	
13492	   ownerdata = SCIPexprGetOwnerData(expr);
13493	   assert(ownerdata != NULL);
13494	
13495	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13496	   assert(conshdlrdata != NULL);
13497	
13498	   if( conshdlrdata->enforound != ownerdata->violscoretag )
13499	      return 0.0;
13500	
13501	   if( ownerdata->nviolscores == 0 )
13502	      return 0.0;
13503	
13504	   switch( conshdlrdata->branchscoreagg )
13505	   {
13506	      case 'a' :
13507	         /* average */
13508	         return ownerdata->violscoresum / ownerdata->nviolscores;
13509	
13510	      case 'm' :
13511	         /* maximum */
13512	         return ownerdata->violscoremax;
13513	
13514	      case 's' :
13515	         /* sum */
13516	         return ownerdata->violscoresum;
13517	
13518	      default:
13519	         SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
13520	         SCIPABORT();
13521	         return SCIP_INVALID;
13522	   }
13523	}
13524	
13525	/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13526	 *
13527	 * @see SCIPexprGetDerivative()
13528	 */
13529	SCIP_Real SCIPgetExprPartialDiffNonlinear(
13530	   SCIP*                 scip,               /**< SCIP data structure */
13531	   SCIP_EXPR*            expr,               /**< root expression of constraint used in the last SCIPevalExprGradient() call */
13532	   SCIP_VAR*             var                 /**< variable (needs to be in the expression) */
13533	   )
13534	{
13535	   SCIP_EXPR_OWNERDATA* ownerdata;
13536	   SCIP_CONSHDLRDATA* conshdlrdata;
13537	   SCIP_EXPR* varexpr;
13538	
13539	   assert(scip != NULL);
13540	   assert(expr != NULL);
13541	   assert(var != NULL);
13542	
13543	   /* return 0.0 for value expression */
13544	   if( SCIPisExprValue(scip, expr) )
13545	   {
13546	      assert(SCIPexprGetDerivative(expr) == 0.0);
13547	      return 0.0;
13548	   }
13549	
13550	   /* check if an error occurred during the last SCIPevalExprGradient() call */
13551	   if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
13552	      return SCIP_INVALID;
13553	
13554	   ownerdata = SCIPexprGetOwnerData(expr);
13555	   assert(ownerdata != NULL);
13556	
13557	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13558	   assert(conshdlrdata != NULL);
13559	
13560	   /* use variable to expressions mapping which is stored in the constraint handler data */
13561	   assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13562	
13563	   varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13564	   assert(varexpr != NULL);
13565	   assert(SCIPisExprVar(scip, varexpr));
13566	
13567	   /* use difftag to decide whether the variable belongs to the expression */
13568	   return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
13569	}
13570	
13571	/** 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)
13572	 *
13573	 * @see SCIPexprGetBardot()
13574	 */
13575	SCIP_Real SCIPgetExprPartialDiffGradientDirNonlinear(
13576	   SCIP*                 scip,               /**< SCIP data structure */
13577	   SCIP_EXPR*            expr,               /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
13578	   SCIP_VAR*             var                 /**< variable (needs to be in the expression) */
13579	   )
13580	{
13581	   SCIP_EXPR_OWNERDATA* ownerdata;
13582	   SCIP_CONSHDLRDATA* conshdlrdata;
13583	   SCIP_EXPR* varexpr;
13584	
13585	   assert(scip != NULL);
13586	   assert(expr != NULL);
13587	   assert(var != NULL);
13588	
13589	   /* return 0.0 for value expression */
13590	   if( SCIPisExprValue(scip, expr) )
13591	      return 0.0;
13592	
13593	   /* check if an error occurred during the last SCIPevalExprHessianDir() call */
13594	   if( SCIPexprGetBardot(expr) == SCIP_INVALID )
13595	      return SCIP_INVALID;
13596	
13597	   ownerdata = SCIPexprGetOwnerData(expr);
13598	   assert(ownerdata != NULL);
13599	
13600	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13601	   assert(conshdlrdata != NULL);
13602	
13603	   /* use variable to expressions mapping which is stored in the constraint handler data;
13604	    * if this fails it means that we are asking for the var's component of H*u for a var
13605	    * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
13606	    */
13607	   assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13608	
13609	   varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13610	   assert(varexpr != NULL);
13611	   assert(SCIPisExprVar(scip, varexpr));
13612	
13613	   /* use difftag to decide whether the variable belongs to the expression */
13614	   return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
13615	}
13616	
13617	/** evaluates quadratic term in a solution w.r.t. auxiliary variables
13618	 *
13619	 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
13620	 */
13621	SCIP_Real SCIPevalExprQuadraticAuxNonlinear(
13622	   SCIP*                 scip,               /**< SCIP data structure */
13623	   SCIP_EXPR*            expr,               /**< quadratic expression */
13624	   SCIP_SOL*             sol                 /**< solution to evaluate, or NULL for LP solution */
13625	   )
13626	{
13627	   SCIP_Real auxvalue;
13628	   int nlinexprs;
13629	   SCIP_Real* lincoefs;
13630	   SCIP_EXPR** linexprs;
13631	   int nquadexprs;
13632	   int nbilinexprs;
13633	   int i;
13634	
13635	   assert(scip != NULL);
13636	   assert(expr != NULL);
13637	
13638	   SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
13639	
13640	   /* linear terms */
13641	   for( i = 0; i < nlinexprs; ++i )
13642	   {
13643	      assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
13644	      auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
13645	   }
13646	
13647	   /* quadratic terms */
13648	   for( i = 0; i < nquadexprs; ++i )
13649	   {
13650	      SCIP_EXPR* quadexprterm;
13651	      SCIP_Real lincoef;
13652	      SCIP_Real sqrcoef;
13653	      SCIP_Real solval;
13654	
13655	      SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
13656	
13657	      assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
13658	
13659	      solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
13660	      auxvalue += (lincoef + sqrcoef * solval) * solval;
13661	   }
13662	
13663	   /* bilinear terms */
13664	   for( i = 0; i < nbilinexprs; ++i )
13665	   {
13666	      SCIP_EXPR* expr1;
13667	      SCIP_EXPR* expr2;
13668	      SCIP_Real coef;
13669	
13670	      SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
13671	
13672	      assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
13673	      assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
13674	      auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
13675	   }
13676	
13677	   return auxvalue;
13678	}
13679	
13680	/**@addtogroup PublicNlhdlrInterfaceMethods
13681	 * @{
13682	 */
13683	
13684	/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
13685	SCIP_RETCODE SCIPincludeNlhdlrNonlinear(
13686	   SCIP*                 scip,               /**< SCIP data structure */
13687	   SCIP_NLHDLR**         nlhdlr,             /**< buffer where to store nonlinear handler */
13688	   const char*           name,               /**< name of nonlinear handler (must not be NULL) */
13689	   const char*           desc,               /**< description of nonlinear handler (can be NULL) */
13690	   int                   detectpriority,     /**< detection priority of nonlinear handler */
13691	   int                   enfopriority,       /**< enforcement priority of nonlinear handler */
13692	   SCIP_DECL_NLHDLRDETECT((*detect)),        /**< structure detection callback of nonlinear handler */
13693	   SCIP_DECL_NLHDLREVALAUX((*evalaux)),      /**< auxiliary evaluation callback of nonlinear handler */
13694	   SCIP_NLHDLRDATA*      nlhdlrdata          /**< data of nonlinear handler (can be NULL) */
13695	   )
13696	{
13697	   SCIP_CONSHDLR* conshdlr;
13698	   SCIP_CONSHDLRDATA* conshdlrdata;
13699	
13700	   assert(scip != NULL);
13701	   assert(nlhdlr != NULL);
13702	   assert(detect != NULL);
13703	
13704	   /* find myself */
13705	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13706	   if( conshdlr == NULL )
13707	   {
13708	      SCIPerrorMessage("nonlinear constraint handler not found");
13709	      return SCIP_PLUGINNOTFOUND;
13710	   }
13711	
13712	   /* create nlhdlr */
13713	   SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
13714	
13715	   /* include into constraint handler */
13716	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13717	   assert(conshdlrdata != NULL);
13718	
13719	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
13720	
13721	   conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
13722	   ++conshdlrdata->nnlhdlrs;
13723	
13724	   /* sort nonlinear handlers by detection priority, in decreasing order
13725	    * will happen in INIT, so only do when called late
13726	    */
13727	   if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
13728	      SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
13729	
13730	   return SCIP_OKAY;
13731	}
13732	
13733	/** get number of nonlinear handler */
13734	int SCIPgetNNlhdlrsNonlinear(
13735	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
13736	   )
13737	{
13738	   SCIP_CONSHDLRDATA* conshdlrdata;
13739	
13740	   assert(conshdlr != NULL);
13741	
13742	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13743	   assert(conshdlrdata != NULL);
13744	
13745	   return conshdlrdata->nnlhdlrs;
13746	}
13747	
13748	/** get nonlinear handlers */
13749	SCIP_NLHDLR** SCIPgetNlhdlrsNonlinear(
13750	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
13751	   )
13752	{
13753	   SCIP_CONSHDLRDATA* conshdlrdata;
13754	
13755	   assert(conshdlr != NULL);
13756	
13757	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13758	   assert(conshdlrdata != NULL);
13759	
13760	   return conshdlrdata->nlhdlrs;
13761	}
13762	
13763	/** returns a nonlinear handler of a given name (or NULL if not found) */
13764	SCIP_NLHDLR* SCIPfindNlhdlrNonlinear(
13765	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
13766	   const char*           name                /**< name of nonlinear handler */
13767	   )
13768	{
13769	   SCIP_CONSHDLRDATA* conshdlrdata;
13770	   int h;
13771	
13772	   assert(conshdlr != NULL);
13773	   assert(name != NULL);
13774	
13775	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13776	   assert(conshdlrdata != NULL);
13777	
13778	   for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
13779	      if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
13780	         return conshdlrdata->nlhdlrs[h];
13781	
13782	   return NULL;
13783	}
13784	
13785	/** gives expression data that a given nonlinear handler stored in an expression
13786	 *
13787	 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
13788	 */
13789	SCIP_NLHDLREXPRDATA* SCIPgetNlhdlrExprDataNonlinear(
13790	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
13791	   SCIP_EXPR*            expr                /**< expression */
13792	   )
13793	{
13794	   SCIP_EXPR_OWNERDATA* ownerdata;
13795	   int e;
13796	
13797	   assert(nlhdlr != NULL);
13798	   assert(expr != NULL);
13799	
13800	   ownerdata = SCIPexprGetOwnerData(expr);
13801	   assert(ownerdata != NULL);
13802	
13803	   for( e = 0; e < ownerdata->nenfos; ++e )
13804	      if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
13805	         return ownerdata->enfos[e]->nlhdlrexprdata;
13806	
13807	   return NULL;
13808	}
13809	
13810	/** @} */
13811