1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2021 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  	
305  	   /* statistics */
306  	   SCIP_Longint          nweaksepa;          /**< number of times we used "weak" cuts for enforcement */
307  	   SCIP_Longint          ntightenlp;         /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
308  	   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 */
309  	   SCIP_Longint          ndesperatebranch;   /**< number of times we branched on some variable because normal enforcement was not successful */
310  	   SCIP_Longint          ndesperatecutoff;   /**< number of times we cut off a node in enforcement because no branching candidate could be found */
311  	   SCIP_Longint          nforcelp;           /**< number of times we forced solving the LP when enforcing a pseudo solution */
312  	   SCIP_CLOCK*           canonicalizetime;   /**< time spend for canonicalization */
313  	   SCIP_Longint          ncanonicalizecalls; /**< number of times we called canonicalization */
314  	
315  	   /* facets of envelops of vertex-polyhedral functions */
316  	   SCIP_RANDNUMGEN*      vp_randnumgen;      /**< random number generator used to perturb reference point */
317  	   SCIP_LPI*             vp_lp[SCIP_MAXVERTEXPOLYDIM+1];  /**< LPs used to compute facets for functions of different dimension */
318  	
319  	   /* hashing of bilinear terms */
320  	   SCIP_HASHTABLE*       bilinhashtable;     /**< hash table for bilinear terms */
321  	   SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
322  	   int                   nbilinterms;        /**< total number of bilinear terms */
323  	   int                   bilintermssize;     /**< size of bilinterms array */
324  	   int                   bilinmaxnauxexprs;  /**< maximal number of auxiliary expressions per bilinear term */
325  	
326  	   /* branching */
327  	   SCIP_RANDNUMGEN*      branchrandnumgen;   /**< random number generated used in branching variable selection */
328  	   char                  branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
329  	
330  	   /* misc */
331  	   SCIP_Bool             checkedvarlocks;    /**< whether variables contained in a single constraint have been already considered */
332  	   SCIP_HASHMAP*         var2expr;           /**< hashmap to map SCIP variables to variable-expressions */
333  	   int                   newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
334  	};
335  	
336  	/** branching candidate with various scores */
337  	typedef struct
338  	{
339  	   SCIP_EXPR*            expr;               /**< expression that holds branching candidate */
340  	   SCIP_Real             auxviol;            /**< aux-violation score of candidate */
341  	   SCIP_Real             domain;             /**< domain score of candidate */
342  	   SCIP_Real             dual;               /**< dual score of candidate */
343  	   SCIP_Real             pscost;             /**< pseudo-cost score of candidate */
344  	   SCIP_Real             vartype;            /**< variable type score of candidate */
345  	   SCIP_Real             weighted;           /**< weighted sum of other scores, see scoreBranchingCandidates() */
346  	} BRANCHCAND;
347  	
348  	/*
349  	 * Local methods
350  	 */
351  	
352  	/* forward declaration */
353  	static
354  	SCIP_RETCODE forwardPropExpr(
355  	   SCIP*                 scip,               /**< SCIP data structure */
356  	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
357  	   SCIP_EXPR*            rootexpr,           /**< expression */
358  	   SCIP_Bool             tightenauxvars,     /**< should the bounds of auxiliary variables be tightened? */
359  	   SCIP_Bool*            infeasible,         /**< buffer to store whether the problem is infeasible (NULL if not needed) */
360  	   int*                  ntightenings        /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
361  	   );
362  	
363  	/** frees auxiliary variables of expression, if any */
364  	static
365  	SCIP_RETCODE freeAuxVar(
366  	   SCIP*                 scip,               /**< SCIP data structure */
367  	   SCIP_EXPR*            expr                /**< expression which auxvar to free, if any */
368  	   )
369  	{
370  	   SCIP_EXPR_OWNERDATA* mydata;
371  	
372  	   assert(scip != NULL);
373  	   assert(expr != NULL);
374  	
375  	   mydata = SCIPexprGetOwnerData(expr);
376  	   assert(mydata != NULL);
377  	
378  	   if( mydata->auxvar == NULL )
379  	      return SCIP_OKAY;
380  	
381  	   SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
382  	
383  	   /* remove variable locks
384  	    * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
385  	    */
386  	   SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
387  	
388  	   /* release auxiliary variable */
389  	   SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
390  	   assert(mydata->auxvar == NULL);
391  	
392  	   return SCIP_OKAY;
393  	}
394  	
395  	/** frees data used for enforcement of expression, that is, nonlinear handlers
396  	 *
397  	 * can also clear indicators whether expr needs enforcement methods, that is,
398  	 * free an associated auxiliary variable and reset the nactivityuses counts
399  	 */
400  	static
401  	SCIP_RETCODE freeEnfoData(
402  	   SCIP*                 scip,               /**< SCIP data structure */
403  	   SCIP_EXPR*            expr,               /**< expression whose enforcement data will be released */
404  	   SCIP_Bool             freeauxvar          /**< whether aux var should be released and activity usage counts be reset */
405  	   )
406  	{
407  	   SCIP_EXPR_OWNERDATA* mydata;
408  	   int e;
409  	
410  	   mydata = SCIPexprGetOwnerData(expr);
411  	   assert(mydata != NULL);
412  	
413  	   if( freeauxvar )
414  	   {
415  	      /* free auxiliary variable */
416  	      SCIP_CALL( freeAuxVar(scip, expr) );
417  	      assert(mydata->auxvar == NULL);
418  	
419  	      /* reset count on activity and auxvar usage */
420  	      mydata->nactivityusesprop = 0;
421  	      mydata->nactivityusessepa = 0;
422  	      mydata->nauxvaruses = 0;
423  	   }
424  	
425  	   /* free data stored by nonlinear handlers */
426  	   for( e = 0; e < mydata->nenfos; ++e )
427  	   {
428  	      SCIP_NLHDLR* nlhdlr;
429  	
430  	      assert(mydata->enfos[e] != NULL);
431  	
432  	      nlhdlr = mydata->enfos[e]->nlhdlr;
433  	      assert(nlhdlr != NULL);
434  	
435  	      if( mydata->enfos[e]->issepainit )
436  	      {
437  	         /* call the separation deinitialization callback of the nonlinear handler */
438  	         SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
439  	         mydata->enfos[e]->issepainit = FALSE;
440  	      }
441  	
442  	      /* free nlhdlr exprdata, if there is any and there is a method to free this data */
443  	      if( mydata->enfos[e]->nlhdlrexprdata != NULL )
444  	      {
445  	         SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
446  	         assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
447  	      }
448  	
449  	      /* free enfo data */
450  	      SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
451  	   }
452  	
453  	   /* free array with enfo data */
454  	   SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
455  	
456  	   /* we need to look at this expression in detect again */
457  	   mydata->nenfos = -1;
458  	
459  	   return SCIP_OKAY;
460  	}
461  	
462  	/** callback that frees data that this conshdlr stored in an expression */
463  	static
464  	SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
465  	{
466  	   assert(scip != NULL);
467  	   assert(expr != NULL);
468  	   assert(ownerdata != NULL);
469  	   assert(*ownerdata != NULL);
470  	
471  	   /* expression should not be locked anymore */
472  	   assert((*ownerdata)->nlockspos == 0);
473  	   assert((*ownerdata)->nlocksneg == 0);
474  	
475  	   SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
476  	
477  	   /* expression should not be enforced anymore */
478  	   assert((*ownerdata)->nenfos <= 0);
479  	   assert((*ownerdata)->auxvar == NULL);
480  	
481  	   if( SCIPisExprVar(scip, expr) )
482  	   {
483  	      SCIP_CONSHDLRDATA* conshdlrdata;
484  	      SCIP_VAR* var;
485  	
486  	      /* there should be no constraints left that still use this variable */
487  	      assert((*ownerdata)->nconss == 0);
488  	      /* thus, there should also be no variable event catched (via this exprhdlr) */
489  	      assert((*ownerdata)->filterpos == -1);
490  	
491  	      SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
492  	
493  	      /* update var2expr hashmap in conshdlrdata */
494  	      conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
495  	      assert(conshdlrdata != NULL);
496  	
497  	      var = SCIPgetVarExprVar(expr);
498  	      assert(var != NULL);
499  	
500  	      /* remove var -> expr map from hashmap if present
501  	       *  (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
502  	       *   if variable-expression stored for var is different, then also do nothing)
503  	       */
504  	      if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
505  	      {
506  	         SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
507  	      }
508  	   }
509  	
510  	   SCIPfreeBlockMemory(scip, ownerdata);
511  	
512  	   return SCIP_OKAY;
513  	}
514  	
515  	static
516  	SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
517  	{  /*lint --e{715}*/
518  	   assert(ownerdata != NULL);
519  	
520  	   /* print nl handlers associated to expr */
521  	   if( ownerdata->nenfos > 0 )
522  	   {
523  	      int i;
524  	      SCIPinfoMessage(scip, file, "   {");
525  	
526  	      for( i = 0; i < ownerdata->nenfos; ++i )
527  	      {
528  	         SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
529  	         if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
530  	            SCIPinfoMessage(scip, file, "a");
531  	         if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
532  	            SCIPinfoMessage(scip, file, "u");
533  	         if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
534  	            SCIPinfoMessage(scip, file, "o");
535  	         if( i < ownerdata->nenfos-1 )
536  	            SCIPinfoMessage(scip, file, ", ");
537  	      }
538  	
539  	      SCIPinfoMessage(scip, file, "}");
540  	   }
541  	
542  	   /* print aux var associated to expr */
543  	   if( ownerdata->auxvar != NULL )
544  	   {
545  	      SCIPinfoMessage(scip, file, "  (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
546  	   }
547  	   SCIPinfoMessage(scip, file, "\n");
548  	
549  	   return SCIP_OKAY;
550  	}
551  	
552  	/** possibly reevaluates and then returns the activity of the expression
553  	 *
554  	 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
555  	 */
556  	static
557  	SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
558  	{
559  	   SCIP_CONSHDLRDATA* conshdlrdata;
560  	
561  	   assert(scip != NULL);
562  	   assert(expr != NULL);
563  	   assert(ownerdata != NULL);
564  	
565  	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
566  	   assert(conshdlrdata != NULL);
567  	
568  	   if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
569  	   {
570  	      /* update activity of expression */
571  	      SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
572  	
573  	      assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
574  	   }
575  	
576  	   return SCIP_OKAY;
577  	}
578  	
579  	/** callback that creates data that this conshdlr wants to store in an expression */
580  	static
581  	SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
582  	{
583  	   assert(scip != NULL);
584  	   assert(expr != NULL);
585  	   assert(ownerdata != NULL);
586  	
587  	   SCIP_CALL( SCIPallocClearBlockMemory(scip, ownerdata) );
588  	   (*ownerdata)->nenfos = -1;
589  	   (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
590  	
591  	   if( SCIPisExprVar(scip, expr) )
592  	   {
593  	      SCIP_CONSHDLRDATA* conshdlrdata;
594  	      SCIP_VAR* var;
595  	
596  	      (*ownerdata)->filterpos = -1;
597  	
598  	      /* add to var2expr hashmap if not having expr for var yet */
599  	
600  	      conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
601  	      assert(conshdlrdata != NULL);
602  	
603  	      var = SCIPgetVarExprVar(expr);
604  	
605  	      if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
606  	      {
607  	         /* store the variable expression in the hashmap */
608  	         SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
609  	      }
610  	      else
611  	      {
612  	         /* if expr was just created, then it shouldn't already be stored as image of var */
613  	         assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
614  	      }
615  	   }
616  	   else
617  	   {
618  	      /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
619  	      (*ownerdata)->filterpos = -2;
620  	   }
621  	
622  	   *ownerfree = exprownerFree;
623  	   *ownerprint = exprownerPrint;
624  	   *ownerevalactivity = exprownerEvalactivity;
625  	
626  	   return SCIP_OKAY;
627  	}
628  	
629  	/** creates a variable expression or retrieves from hashmap in conshdlr data */
630  	static
631  	SCIP_RETCODE createExprVar(
632  	   SCIP*                 scip,               /**< SCIP data structure */
633  	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
634  	   SCIP_EXPR**           expr,               /**< pointer where to store expression */
635  	   SCIP_VAR*             var                 /**< variable to be stored */
636  	   )
637  	{
638  	   assert(conshdlr != NULL);
639  	   assert(expr != NULL);
640  	   assert(var != NULL);
641  	
642  	   /* get variable expression representing the given variable if there is one already */
643  	   *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
644  	
645  	   if( *expr == NULL )
646  	   {
647  	      /* create a new variable expression; this also captures the expression */
648  	      SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
649  	      assert(*expr != NULL);
650  	      /* exprownerCreate should have added var->expr to var2expr */
651  	      assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
652  	   }
653  	   else
654  	   {
655  	      /* only capture already existing expr to get a consistent uses-count */
656  	      SCIPcaptureExpr(*expr);
657  	   }
658  	
659  	   return SCIP_OKAY;
660  	}
661  	
662  	/* map var exprs to var-expr from var2expr hashmap */
663  	static
664  	SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
665  	{  /*lint --e{715}*/
666  	   SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
667  	
668  	   assert(sourcescip != NULL);
669  	   assert(targetscip != NULL);
670  	   assert(sourceexpr != NULL);
671  	   assert(targetexpr != NULL);
672  	   assert(*targetexpr == NULL);
673  	   assert(mapexprdata != NULL);
674  	
675  	   /* do not provide map if not variable */
676  	   if( !SCIPisExprVar(sourcescip, sourceexpr) )
677  	      return SCIP_OKAY;
678  	
679  	   SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
680  	
681  	   return SCIP_OKAY;
682  	}
683  	
684  	/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
685  	static
686  	SCIP_DECL_EXPR_MAPEXPR(mapexprtransvar)
687  	{  /*lint --e{715}*/
688  	   SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
689  	   SCIP_VAR* var;
690  	
691  	   assert(sourcescip != NULL);
692  	   assert(targetscip != NULL);
693  	   assert(sourceexpr != NULL);
694  	   assert(targetexpr != NULL);
695  	   assert(*targetexpr == NULL);
696  	   assert(mapexprdata != NULL);
697  	
698  	   /* do not provide map if not variable */
699  	   if( !SCIPisExprVar(sourcescip, sourceexpr) )
700  	      return SCIP_OKAY;
701  	
702  	   var = SCIPgetVarExprVar(sourceexpr);
703  	   assert(var != NULL);
704  	
705  	   /* transform variable */
706  	   SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
707  	   assert(var != NULL);
708  	
709  	   SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
710  	
711  	   return SCIP_OKAY;
712  	}
713  	
714  	/** stores all variable expressions into a given constraint */
715  	static
716  	SCIP_RETCODE storeVarExprs(
717  	   SCIP*                 scip,               /**< SCIP data structure */
718  	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
719  	   SCIP_CONSDATA*        consdata            /**< constraint data */
720  	   )
721  	{
722  	   SCIP_CONSHDLRDATA* conshdlrdata;
723  	   int i;
724  	
725  	   assert(consdata != NULL);
726  	
727  	   /* skip if we have stored the variable expressions already */
728  	   if( consdata->varexprs != NULL )
729  	      return SCIP_OKAY;
730  	
731  	   assert(consdata->varexprs == NULL);
732  	   assert(consdata->nvarexprs == 0);
733  	
734  	   /* create array to store all variable expressions; the number of variable expressions is bounded by SCIPgetNTotalVars() */
735  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, SCIPgetNTotalVars(scip)) );
736  	
737  	   SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
738  	   assert(SCIPgetNTotalVars(scip) >= consdata->nvarexprs);
739  	
740  	   /* shrink array if there are less variables in the expression than in the problem */
741  	   if( SCIPgetNTotalVars(scip) > consdata->nvarexprs )
742  	   {
743  	      SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, SCIPgetNTotalVars(scip), consdata->nvarexprs) );
744  	   }
745  	
746  	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
747  	   assert(conshdlrdata != NULL);
748  	   assert(conshdlrdata->var2expr != NULL);
749  	
750  	   /* ensure that for every variable an entry exists in the var2expr hashmap
751  	    * when removing duplicate subexpressions it can happen than a var->varexpr map was removed from the hashmap
752  	    */
753  	   for( i = 0; i < consdata->nvarexprs; ++i )
754  	   {
755  	      if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
756  	      {
757  	         SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
758  	      }
759  	   }
760  	
761  	   return SCIP_OKAY;
762  	}
763  	
764  	/** frees all variable expression stored in storeVarExprs() */
765  	static
766  	SCIP_RETCODE freeVarExprs(
767  	   SCIP*                 scip,               /**< SCIP data structure */
768  	   SCIP_CONSDATA*        consdata            /**< constraint data */
769  	   )
770  	{
771  	   int i;
772  	
773  	   assert(consdata != NULL);
774  	
775  	   /* skip if we have stored the variable expressions already*/
776  	   if( consdata->varexprs == NULL )
777  	      return SCIP_OKAY;
778  	
779  	   assert(consdata->varexprs != NULL);
780  	   assert(consdata->nvarexprs >= 0);
781  	
782  	   /* release variable expressions */
783  	   for( i = 0; i < consdata->nvarexprs; ++i )
784  	   {
785  	      assert(consdata->varexprs[i] != NULL);
786  	      SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
787  	      assert(consdata->varexprs[i] == NULL);
788  	   }
789  	
790  	   /* free variable expressions */
791  	   SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
792  	   consdata->varexprs = NULL;
793  	   consdata->nvarexprs = 0;
794  	
795  	   return SCIP_OKAY;
796  	}
797  	
798  	/** interval evaluation of variables as used in bound tightening
799  	 *
800  	 * Returns slightly relaxed local variable bounds of a variable as interval.
801  	 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
802  	 */
803  	static
804  	SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
805  	{
806  	   SCIP_INTERVAL interval;
807  	   SCIP_CONSHDLRDATA* conshdlrdata;
808  	   SCIP_Real lb;
809  	   SCIP_Real ub;
810  	
811  	   assert(scip != NULL);
812  	   assert(var != NULL);
813  	
814  	   conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
815  	   assert(conshdlrdata != NULL);
816  	
817  	   if( conshdlrdata->globalbounds )
818  	   {
819  	      lb = SCIPvarGetLbGlobal(var);
820  	      ub = SCIPvarGetUbGlobal(var);
821  	   }
822  	   else
823  	   {
824  	      lb = SCIPvarGetLbLocal(var);
825  	      ub = SCIPvarGetUbLocal(var);
826  	   }
827  	   assert(lb <= ub);  /* SCIP should ensure that variable bounds are not contradicting */
828  	
829  	   /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
830  	   if( SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT )
831  	   {
832  	      lb = EPSROUND(lb, 0.0); /*lint !e835*/
833  	      ub = EPSROUND(ub, 0.0); /*lint !e835*/
834  	   }
835  	
836  	   /* integer variables should always have integral bounds in SCIP */
837  	   assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var));  /*lint !e835*/
838  	   assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var));  /*lint !e835*/
839  	
840  	   switch( conshdlrdata->varboundrelax )
841  	   {
842  	      case 'n' : /* no relaxation */
843  	         break;
844  	
845  	      case 'a' : /* relax by absolute value */
846  	      {
847  	         /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
848  	         if( SCIPvarIsIntegral(var) )
849  	            break;
850  	
851  	         if( !SCIPisInfinity(scip, -lb) )
852  	         {
853  	            /* reduce lb by epsilon, or to the next integer value, which ever is larger */
854  	            SCIP_Real bnd = floor(lb);
855  	            lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
856  	         }
857  	
858  	         if( !SCIPisInfinity(scip, ub) )
859  	         {
860  	            /* increase ub by epsilon, or to the next integer value, which ever is smaller */
861  	            SCIP_Real bnd = ceil(ub);
862  	            ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
863  	         }
864  	
865  	         break;
866  	      }
867  	
868  	      case 'b' : /* relax always by absolute value */
869  	      {
870  	         /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
871  	         if( SCIPvarIsIntegral(var) )
872  	            break;
873  	
874  	         if( !SCIPisInfinity(scip, -lb) )
875  	            lb -= conshdlrdata->varboundrelaxamount;
876  	
877  	         if( !SCIPisInfinity(scip, ub) )
878  	            ub += conshdlrdata->varboundrelaxamount;
879  	
880  	         break;
881  	      }
882  	
883  	      case 'r' : /* relax by relative 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  	         /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
890  	          * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
891  	          * further, do not relax beyond next integer value
892  	          */
893  	         if( !SCIPisInfinity(scip, -lb) )
894  	         {
895  	            SCIP_Real bnd = floor(lb);
896  	            lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
897  	         }
898  	
899  	         if( !SCIPisInfinity(scip, ub) )
900  	         {
901  	            SCIP_Real bnd = ceil(ub);
902  	            ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
903  	         }
904  	
905  	         break;
906  	      }
907  	
908  	      default :
909  	      {
910  	         SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
911  	         SCIPABORT();
912  	         break;
913  	      }
914  	   }
915  	
916  	   /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
917  	   lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
918  	   ub =  infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, ub);
919  	   assert(lb <= ub);
920  	
921  	   SCIPintervalSetBounds(&interval, lb, ub);
922  	
923  	   return interval;
924  	}
925  	
926  	/** compares two nonlinear constraints by its index
927  	 *
928  	 * Usable as compare operator in array sort functions.
929  	 */
930  	static
931  	SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
932  	{
933  	   SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
934  	   SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
935  	
936  	   assert(consdata1 != NULL);
937  	   assert(consdata2 != NULL);
938  	
939  	   return consdata1->consindex - consdata2->consindex;
940  	}
941  	
942  	/** processes variable fixing or bound change event */
943  	static
944  	SCIP_DECL_EVENTEXEC(processVarEvent)
945  	{  /*lint --e{715}*/
946  	   SCIP_EVENTTYPE eventtype;
947  	   SCIP_EXPR* expr;
948  	   SCIP_EXPR_OWNERDATA* ownerdata;
949  	
950  	   eventtype = SCIPeventGetType(event);
951  	   assert(eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED));
952  	
953  	   assert(eventdata != NULL);
954  	   expr = (SCIP_EXPR*) eventdata;
955  	   assert(SCIPisExprVar(scip, expr));
956  	
957  	   SCIPdebugMsg(scip, "  exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
958  	         SCIPvarGetName(SCIPeventGetVar(event)),
959  	         SCIPvarGetLbLocal(SCIPeventGetVar(event)), SCIPvarGetUbLocal(SCIPeventGetVar(event)),
960  	         SCIPvarGetLbGlobal(SCIPeventGetVar(event)), SCIPvarGetUbGlobal(SCIPeventGetVar(event)));
961  	
962  	   ownerdata = SCIPexprGetOwnerData(expr);
963  	   assert(ownerdata != NULL);
964  	   /* we only catch varevents for variables in constraints, so there should be constraints */
965  	   assert(ownerdata->nconss > 0);
966  	   assert(ownerdata->conss != NULL);
967  	
968  	   /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
969  	    * - propagation can only find something new if a bound was tightened
970  	    * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
971  	    *   and we look at global changes (that is, we are not looking at boundchanges in probing)
972  	    */
973  	   if( eventtype & (SCIP_EVENTTYPE_BOUNDTIGHTENED | SCIP_EVENTTYPE_VARFIXED) )
974  	   {
975  	      SCIP_CONSDATA* consdata;
976  	      int c;
977  	
978  	      for( c = 0; c < ownerdata->nconss; ++c )
979  	      {
980  	         assert(ownerdata->conss[c] != NULL);
981  	         consdata = SCIPconsGetData(ownerdata->conss[c]);
982  	
983  	         /* if bound tightening, then mark constraints to be propagated again
984  	          * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
985  	          *   that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
986  	          *   the locks don't help since they are not available separately for each constraint
987  	          */
988  	         if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
989  	         {
990  	            consdata->ispropagated = FALSE;
991  	            SCIPdebugMsg(scip, "  marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
992  	         }
993  	
994  	         /* if still in presolve (but not probing), then mark constraints to be unsimplified */
995  	         if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !SCIPinProbing(scip) )
996  	         {
997  	            consdata->issimplified = FALSE;
998  	            SCIPdebugMsg(scip, "  marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
999  	         }
1000 	      }
1001 	   }
1002 	
1003 	   /* update curboundstag, lastboundrelax, and expr activity */
1004 	   if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1005 	   {
1006 	      SCIP_CONSHDLRDATA* conshdlrdata;
1007 	      SCIP_INTERVAL activity;
1008 	
1009 	      conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1010 	      assert(conshdlrdata != NULL);
1011 	
1012 	      /* increase tag on bounds */
1013 	      ++conshdlrdata->curboundstag;
1014 	      assert(conshdlrdata->curboundstag > 0);
1015 	
1016 	      /* remember also if we relaxed bounds now */
1017 	      if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1018 	         conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1019 	
1020 	      /* update the activity of the var-expr here immediately
1021 	       * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1022 	       */
1023 	      SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1024 	      /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1025 	#ifdef DEBUG_PROP
1026 	      SCIPdebugMsg(scip, "  var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1027 	#endif
1028 	      SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1029 	   }
1030 	
1031 	   return SCIP_OKAY;
1032 	}
1033 	
1034 	/** registers event handler to catch variable events on variable
1035 	 *
1036 	 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1037 	 * When an event occurs, all stored constraints are notified.
1038 	 */
1039 	static
1040 	SCIP_RETCODE catchVarEvent(
1041 	   SCIP*                 scip,               /**< SCIP data structure */
1042 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1043 	   SCIP_EXPR*            expr,               /**< variable expression */
1044 	   SCIP_CONS*            cons                /**< nonlinear constraint */
1045 	   )
1046 	{
1047 	   SCIP_EXPR_OWNERDATA* ownerdata;
1048 	
1049 	   assert(eventhdlr != NULL);
1050 	   assert(expr != NULL);
1051 	   assert(SCIPisExprVar(scip, expr));
1052 	   assert(cons != NULL);
1053 	
1054 	   ownerdata = SCIPexprGetOwnerData(expr);
1055 	   assert(ownerdata != NULL);
1056 	
1057 	#ifndef NDEBUG
1058 	   /* assert that constraint does not double-catch variable */
1059 	   {
1060 	      int i;
1061 	      for( i = 0; i < ownerdata->nconss; ++i )
1062 	         assert(ownerdata->conss[i] != cons);
1063 	   }
1064 	#endif
1065 	
1066 	   /* append cons to ownerdata->conss */
1067 	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1068 	   ownerdata->conss[ownerdata->nconss++] = cons;
1069 	   /* we're not capturing the constraint here to avoid circular references */
1070 	
1071 	   /* updated sorted flag */
1072 	   if( ownerdata->nconss <= 1 )
1073 	      ownerdata->consssorted = TRUE;
1074 	   else if( ownerdata->consssorted )
1075 	      ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1076 	
1077 	   /* catch variable events, if not done so yet (first constraint) */
1078 	   if( ownerdata->filterpos < 0 )
1079 	   {
1080 	      SCIP_EVENTTYPE eventtype;
1081 	
1082 	      assert(ownerdata->nconss == 1);
1083 	
1084 	      eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED;
1085 	
1086 	      SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1087 	      assert(ownerdata->filterpos >= 0);
1088 	   }
1089 	
1090 	   return SCIP_OKAY;
1091 	}
1092 	
1093 	/** catch variable events */
1094 	static
1095 	SCIP_RETCODE catchVarEvents(
1096 	   SCIP*                 scip,               /**< SCIP data structure */
1097 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1098 	   SCIP_CONS*            cons                /**< constraint for which to catch bound change events */
1099 	   )
1100 	{
1101 	   SCIP_CONSHDLRDATA* conshdlrdata;
1102 	   SCIP_CONSDATA* consdata;
1103 	   SCIP_EXPR* expr;
1104 	   int i;
1105 	
1106 	   assert(eventhdlr != NULL);
1107 	   assert(cons != NULL);
1108 	
1109 	   consdata = SCIPconsGetData(cons);
1110 	   assert(consdata != NULL);
1111 	   assert(consdata->varexprs != NULL);
1112 	   assert(consdata->nvarexprs >= 0);
1113 	
1114 	   /* check if we have catched variable events already */
1115 	   if( consdata->catchedevents )
1116 	      return SCIP_OKAY;
1117 	
1118 	   conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1119 	   assert(conshdlrdata != NULL);
1120 	   assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1121 	
1122 	   SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1123 	
1124 	   for( i = 0; i < consdata->nvarexprs; ++i )
1125 	   {
1126 	      expr = consdata->varexprs[i];
1127 	
1128 	      assert(expr != NULL);
1129 	      assert(SCIPisExprVar(scip, expr));
1130 	
1131 	      SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1132 	
1133 	      /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1134 	       * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1135 	       */
1136 	      if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1137 	      {
1138 	         SCIP_INTERVAL activity;
1139 	         SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1140 	         /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1141 	         SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1142 	#ifdef DEBUG_PROP
1143 	         SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1144 	#endif
1145 	      }
1146 	   }
1147 	
1148 	   consdata->catchedevents = TRUE;
1149 	
1150 	   return SCIP_OKAY;
1151 	}
1152 	
1153 	/** unregisters event handler to catch variable events on variable
1154 	 *
1155 	 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1156 	 * If this was the last constraint, then the event handler is unregistered for this variable.
1157 	 */
1158 	static
1159 	SCIP_RETCODE dropVarEvent(
1160 	   SCIP*                 scip,               /**< SCIP data structure */
1161 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1162 	   SCIP_EXPR*            expr,               /**< variable expression */
1163 	   SCIP_CONS*            cons                /**< expr constraint */
1164 	   )
1165 	{
1166 	   SCIP_EXPR_OWNERDATA* ownerdata;
1167 	   int pos;
1168 	
1169 	   assert(eventhdlr != NULL);
1170 	   assert(expr != NULL);
1171 	   assert(SCIPisExprVar(scip, expr));
1172 	   assert(cons != NULL);
1173 	
1174 	   ownerdata = SCIPexprGetOwnerData(expr);
1175 	   assert(ownerdata != NULL);
1176 	   assert(ownerdata->nconss > 0);
1177 	
1178 	   if( ownerdata->conss[ownerdata->nconss-1] == cons )
1179 	   {
1180 	      pos = ownerdata->nconss-1;
1181 	   }
1182 	   else
1183 	   {
1184 	      if( !ownerdata->consssorted )
1185 	      {
1186 	         SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1187 	         ownerdata->consssorted = TRUE;
1188 	      }
1189 	
(9) Event example_checked: Example 1: "SCIPsortedvecFindPtr((void **)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos)" has its value checked in "SCIPsortedvecFindPtr((void **)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos)".
Also see events: [check_return][example_checked][example_assign][example_checked][example_assign][example_checked][example_checked]
1190 	      if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1191 	      {
1192 	         SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1193 	         return SCIP_ERROR;
1194 	      }
1195 	      assert(pos >= 0 && pos < ownerdata->nconss);
1196 	   }
1197 	   assert(ownerdata->conss[pos] == cons);
1198 	
1199 	   /* move last constraint into position of removed constraint */
1200 	   if( pos < ownerdata->nconss-1 )
1201 	   {
1202 	      ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1203 	      ownerdata->consssorted = FALSE;
1204 	   }
1205 	   --ownerdata->nconss;
1206 	
1207 	   /* drop variable events if that was the last constraint */
1208 	   if( ownerdata->nconss == 0 )
1209 	   {
1210 	      SCIP_EVENTTYPE eventtype;
1211 	
1212 	      assert(ownerdata->filterpos >= 0);
1213 	
1214 	      eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED;
1215 	
1216 	      SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1217 	      ownerdata->filterpos = -1;
1218 	   }
1219 	
1220 	   return SCIP_OKAY;
1221 	}
1222 	
1223 	/** drop variable events */
1224 	static
1225 	SCIP_RETCODE dropVarEvents(
1226 	   SCIP*                 scip,               /**< SCIP data structure */
1227 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1228 	   SCIP_CONS*            cons                /**< constraint for which to drop bound change events */
1229 	   )
1230 	{
1231 	   SCIP_CONSDATA* consdata;
1232 	   int i;
1233 	
1234 	   assert(eventhdlr != NULL);
1235 	   assert(cons != NULL);
1236 	
1237 	   consdata = SCIPconsGetData(cons);
1238 	   assert(consdata != NULL);
1239 	
1240 	   /* check if we have catched variable events already */
1241 	   if( !consdata->catchedevents )
1242 	      return SCIP_OKAY;
1243 	
1244 	   assert(consdata->varexprs != NULL);
1245 	   assert(consdata->nvarexprs >= 0);
1246 	
1247 	   SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1248 	
1249 	   for( i = consdata->nvarexprs - 1; i >= 0; --i )
1250 	   {
1251 	      assert(consdata->varexprs[i] != NULL);
1252 	
1253 	      SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1254 	   }
1255 	
1256 	   consdata->catchedevents = FALSE;
1257 	
1258 	   return SCIP_OKAY;
1259 	}
1260 	
1261 	/** creates and captures a nonlinear constraint
1262 	 *
1263 	 * @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
1264 	 */
1265 	static
1266 	SCIP_RETCODE createCons(
1267 	   SCIP*                 scip,               /**< SCIP data structure */
1268 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1269 	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
1270 	   const char*           name,               /**< name of constraint */
1271 	   SCIP_EXPR*            expr,               /**< expression of constraint (must not be NULL) */
1272 	   SCIP_Real             lhs,                /**< left hand side of constraint */
1273 	   SCIP_Real             rhs,                /**< right hand side of constraint */
1274 	   SCIP_Bool             copyexpr,           /**< whether to copy the expression or reuse the given expr (capture it) */
1275 	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
1276 	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1277 	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
1278 	                                              *   Usually set to TRUE. */
1279 	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
1280 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
1281 	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
1282 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
1283 	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
1284 	                                              *   Usually set to TRUE. */
1285 	   SCIP_Bool             local,              /**< is constraint only valid locally?
1286 	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1287 	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
1288 	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
1289 	                                              *   adds coefficients to this constraint. */
1290 	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
1291 	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
1292 	                                              *   are separated as constraints. */
1293 	   SCIP_Bool             removable           /**< should the relaxation be removed from the LP due to aging or cleanup?
1294 	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1295 	   )
1296 	{
1297 	   SCIP_CONSHDLRDATA* conshdlrdata;
1298 	   SCIP_CONSDATA* consdata;
1299 	
1300 	   assert(conshdlr != NULL);
1301 	   assert(expr != NULL);
1302 	
1303 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1304 	   assert(conshdlrdata != NULL);
1305 	
1306 	   if( local && SCIPgetDepth(scip) != 0 )
1307 	   {
1308 	      SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1309 	      return SCIP_INVALIDCALL;
1310 	   }
1311 	
1312 	   /* TODO we should allow for non-initial nonlinear constraints */
1313 	   if( !initial )
1314 	   {
1315 	      SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1316 	      return SCIP_INVALIDCALL;
1317 	   }
1318 	
1319 	   /* create constraint data */
1320 	   SCIP_CALL( SCIPallocClearBlockMemory(scip, &consdata) );
1321 	
1322 	   if( copyexpr )
1323 	   {
1324 	      /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1325 	      SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1326 	   }
1327 	   else
1328 	   {
1329 	      consdata->expr = expr;
1330 	      SCIPcaptureExpr(consdata->expr);
1331 	   }
1332 	   consdata->lhs = lhs;
1333 	   consdata->rhs = rhs;
1334 	   consdata->consindex = conshdlrdata->lastconsindex++;
1335 	   consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1336 	
1337 	   /* create constraint */
1338 	   SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1339 	         local, modifiable, dynamic, removable, FALSE) );
1340 	
1341 	   return SCIP_OKAY;
1342 	}
1343 	
1344 	/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1345 	 *
1346 	 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1347 	 * Assume that f(x) is associated with auxiliary variable z.
1348 	 *
1349 	 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1350 	 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1351 	 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1352 	 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1353 	 *
1354 	 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1355 	 */
1356 	static
1357 	SCIP_Real getExprAbsOrigViolation(
1358 	   SCIP*                 scip,               /**< SCIP data structure */
1359 	   SCIP_EXPR*            expr,               /**< expression */
1360 	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
1361 	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(x) is violated, or NULL */
1362 	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(x) is violated, or NULL */
1363 	   )
1364 	{
1365 	   SCIP_EXPR_OWNERDATA* ownerdata;
1366 	   SCIP_Real auxvarvalue;
1367 	
1368 	   assert(expr != NULL);
1369 	
1370 	   ownerdata = SCIPexprGetOwnerData(expr);
1371 	   assert(ownerdata != NULL);
1372 	   assert(ownerdata->auxvar != NULL);
1373 	
1374 	   if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1375 	   {
1376 	      if( violunder != NULL )
1377 	         *violunder = TRUE;
1378 	      if( violover != NULL )
1379 	         *violover = TRUE;
1380 	      return SCIPinfinity(scip);
1381 	   }
1382 	
1383 	   auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1384 	
1385 	   if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1386 	   {
1387 	      if( violunder != NULL )
1388 	         *violunder = FALSE;
1389 	      if( violover != NULL )
1390 	         *violover = TRUE;
1391 	      return auxvarvalue - SCIPexprGetEvalValue(expr);
1392 	   }
1393 	
1394 	   if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1395 	   {
1396 	      if( violunder != NULL )
1397 	         *violunder = TRUE;
1398 	      if( violover != NULL )
1399 	         *violover = FALSE;
1400 	      return SCIPexprGetEvalValue(expr) - auxvarvalue;
1401 	   }
1402 	
1403 	   if( violunder != NULL )
1404 	      *violunder = FALSE;
1405 	   if( violover != NULL )
1406 	      *violover = FALSE;
1407 	   return 0.0;
1408 	}
1409 	
1410 	/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1411 	 *
1412 	 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1413 	 * Assume that f(w) is associated with auxiliary variable z.
1414 	 *
1415 	 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1416 	 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1417 	 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1418 	 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1419 	 *
1420 	 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1421 	 */
1422 	static
1423 	SCIP_Real getExprAbsAuxViolation(
1424 	   SCIP*                 scip,               /**< SCIP data structure */
1425 	   SCIP_EXPR*            expr,               /**< expression */
1426 	   SCIP_Real             auxvalue,           /**< value of f(w) */
1427 	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
1428 	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(w) is violated, or NULL */
1429 	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(w) is violated, or NULL */
1430 	   )
1431 	{
1432 	   SCIP_EXPR_OWNERDATA* ownerdata;
1433 	   SCIP_Real auxvarvalue;
1434 	
1435 	   assert(expr != NULL);
1436 	
1437 	   ownerdata = SCIPexprGetOwnerData(expr);
1438 	   assert(ownerdata != NULL);
1439 	   assert(ownerdata->auxvar != NULL);
1440 	
1441 	   if( auxvalue == SCIP_INVALID )
1442 	   {
1443 	      if( violunder != NULL )
1444 	         *violunder = TRUE;
1445 	      if( violover != NULL )
1446 	         *violover = TRUE;
1447 	      return SCIPinfinity(scip);
1448 	   }
1449 	
1450 	   auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1451 	
1452 	   if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1453 	   {
1454 	      if( violunder != NULL )
1455 	         *violunder = FALSE;
1456 	      if( violover != NULL )
1457 	         *violover = TRUE;
1458 	      return auxvarvalue - auxvalue;
1459 	   }
1460 	
1461 	   if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1462 	   {
1463 	      if( violunder != NULL )
1464 	         *violunder = TRUE;
1465 	      if( violover != NULL )
1466 	         *violover = FALSE;
1467 	      return auxvalue - auxvarvalue;
1468 	   }
1469 	
1470 	   if( violunder != NULL )
1471 	      *violunder = FALSE;
1472 	   if( violover != NULL )
1473 	      *violover = FALSE;
1474 	
1475 	   return 0.0;
1476 	}
1477 	
1478 	/** computes violation of a constraint */
1479 	static
1480 	SCIP_RETCODE computeViolation(
1481 	   SCIP*                 scip,               /**< SCIP data structure */
1482 	   SCIP_CONS*            cons,               /**< constraint */
1483 	   SCIP_SOL*             sol,                /**< solution or NULL if LP solution should be used */
1484 	   SCIP_Longint          soltag              /**< tag that uniquely identifies the solution (with its values), or 0. */
1485 	   )
1486 	{
1487 	   SCIP_CONSDATA* consdata;
1488 	   SCIP_Real activity;
1489 	
1490 	   assert(scip != NULL);
1491 	   assert(cons != NULL);
1492 	
1493 	   consdata = SCIPconsGetData(cons);
1494 	   assert(consdata != NULL);
1495 	
1496 	   SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1497 	   activity = SCIPexprGetEvalValue(consdata->expr);
1498 	
1499 	   /* consider constraint as violated if it is undefined in the current point */
1500 	   if( activity == SCIP_INVALID )
1501 	   {
1502 	      consdata->lhsviol = SCIPinfinity(scip);
1503 	      consdata->rhsviol = SCIPinfinity(scip);
1504 	      return SCIP_OKAY;
1505 	   }
1506 	
1507 	   /* compute violations */
1508 	   consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs  - activity;
1509 	   consdata->rhsviol = SCIPisInfinity(scip,  consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1510 	
1511 	   return SCIP_OKAY;
1512 	}
1513 	
1514 	/** returns absolute violation of a constraint
1515 	 *
1516 	 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1517 	 */
1518 	static
1519 	SCIP_Real getConsAbsViolation(
1520 	   SCIP_CONS*            cons                /**< constraint */
1521 	   )
1522 	{
1523 	   SCIP_CONSDATA* consdata;
1524 	
1525 	   assert(cons != NULL);
1526 	
1527 	   consdata = SCIPconsGetData(cons);
1528 	   assert(consdata != NULL);
1529 	
1530 	   return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1531 	}
1532 	
1533 	/** computes relative violation of a constraint
1534 	 *
1535 	 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1536 	 */
1537 	static
1538 	SCIP_RETCODE getConsRelViolation(
1539 	   SCIP*                 scip,               /**< SCIP data structure */
1540 	   SCIP_CONS*            cons,               /**< constraint */
1541 	   SCIP_Real*            viol,               /**< buffer to store violation */
1542 	   SCIP_SOL*             sol,                /**< solution or NULL if LP solution should be used */
1543 	   SCIP_Longint          soltag              /**< tag that uniquely identifies the solution (with its values), or 0 */
1544 	   )
1545 	{
1546 	   SCIP_CONSHDLR* conshdlr;
1547 	   SCIP_CONSHDLRDATA* conshdlrdata;
1548 	   SCIP_CONSDATA* consdata;
1549 	   SCIP_Real scale;
1550 	
1551 	   assert(cons != NULL);
1552 	   assert(viol != NULL);
1553 	
1554 	   conshdlr = SCIPconsGetHdlr(cons);
1555 	   assert(conshdlr != NULL);
1556 	
1557 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1558 	   assert(conshdlrdata != NULL);
1559 	
1560 	   *viol = getConsAbsViolation(cons);
1561 	
1562 	   if( conshdlrdata->violscale == 'n' )
1563 	      return SCIP_OKAY;
1564 	
1565 	   if( SCIPisInfinity(scip, *viol) )
1566 	      return SCIP_OKAY;
1567 	
1568 	   consdata = SCIPconsGetData(cons);
1569 	   assert(consdata != NULL);
1570 	
1571 	   if( conshdlrdata->violscale == 'a' )
1572 	   {
1573 	      scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1574 	
1575 	      /* consider value of side that is violated for scaling, too */
1576 	      if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1577 	      {
1578 	         assert(!SCIPisInfinity(scip, -consdata->lhs));
1579 	         scale = REALABS(consdata->lhs);
1580 	      }
1581 	      else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1582 	      {
1583 	         assert(!SCIPisInfinity(scip,  consdata->rhs));
1584 	         scale = REALABS(consdata->rhs);
1585 	      }
1586 	
1587 	      *viol /= scale;
1588 	      return SCIP_OKAY;
1589 	   }
1590 	
1591 	   /* if not 'n' or 'a', then it has to be 'g' at the moment */
1592 	   assert(conshdlrdata->violscale == 'g');
1593 	   if( soltag == 0L || consdata->gradnormsoltag != soltag )
1594 	   {
1595 	      /* we need the varexprs to conveniently access the gradient */
1596 	      SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1597 	
1598 	      /* update cached value of norm of gradient */
1599 	      consdata->gradnorm = 0.0;
1600 	
1601 	      /* compute gradient */
1602 	      SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1603 	
1604 	      /* gradient evaluation error -> no scaling */
1605 	      if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1606 	      {
1607 	         int i;
1608 	         for( i = 0; i < consdata->nvarexprs; ++i )
1609 	         {
1610 	            SCIP_Real deriv;
1611 	
1612 	            assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1613 	            deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1614 	            if( deriv == SCIP_INVALID )
1615 	            {
1616 	               /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1617 	               consdata->gradnorm = 0.0;
1618 	               break;
1619 	            }
1620 	
1621 	            consdata->gradnorm += deriv*deriv;
1622 	         }
1623 	      }
1624 	      consdata->gradnorm = sqrt(consdata->gradnorm);
1625 	      consdata->gradnormsoltag = soltag;
1626 	   }
1627 	
1628 	   *viol /= MAX(1.0, consdata->gradnorm);
1629 	
1630 	   return SCIP_OKAY;
1631 	}
1632 	
1633 	/** returns whether constraint is currently violated
1634 	 *
1635 	 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1636 	 */
1637 	static
1638 	SCIP_Bool isConsViolated(
1639 	   SCIP*                 scip,               /**< SCIP data structure */
1640 	   SCIP_CONS*            cons                /**< constraint */
1641 	   )
1642 	{
1643 	   return getConsAbsViolation(cons) > SCIPfeastol(scip);
1644 	}
1645 	
1646 	/** checks for a linear variable that can be increased or decreased without harming feasibility */
1647 	static
1648 	void findUnlockedLinearVar(
1649 	   SCIP*                 scip,               /**< SCIP data structure */
1650 	   SCIP_CONS*            cons                /**< constraint */
1651 	   )
1652 	{
1653 	   SCIP_CONSDATA* consdata;
1654 	   int poslock;
1655 	   int neglock;
1656 	   int i;
1657 	
1658 	   assert(cons != NULL);
1659 	
1660 	   consdata = SCIPconsGetData(cons);
1661 	   assert(consdata != NULL);
1662 	
1663 	   consdata->linvarincr = NULL;
1664 	   consdata->linvardecr = NULL;
1665 	   consdata->linvarincrcoef = 0.0;
1666 	   consdata->linvardecrcoef = 0.0;
1667 	
1668 	   /* root expression is not a sum -> no unlocked linear variable available */
1669 	   if( !SCIPisExprSum(scip, consdata->expr) )
1670 	      return;
1671 	
1672 	   for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1673 	   {
1674 	      SCIP_EXPR* child;
1675 	
1676 	      child = SCIPexprGetChildren(consdata->expr)[i];
1677 	      assert(child != NULL);
1678 	
1679 	      /* check whether the child is a variable expression */
1680 	      if( SCIPisExprVar(scip, child) )
1681 	      {
1682 	         SCIP_VAR* var = SCIPgetVarExprVar(child);
1683 	         SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1684 	
1685 	         if( coef > 0.0 )
1686 	         {
1687 	            poslock = !SCIPisInfinity(scip,  consdata->rhs) ? 1 : 0;
1688 	            neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1689 	         }
1690 	         else
1691 	         {
1692 	            poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1693 	            neglock = !SCIPisInfinity(scip,  consdata->rhs) ? 1 : 0;
1694 	         }
1695 	         SCIPdebugMsg(scip, "child <%s> locks: %d %d\n", SCIPvarGetName(var), SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL), SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL));
1696 	
1697 	         if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1698 	         {
1699 	            /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1700 	             * if we have already one candidate, then take the one where the loss in the objective function is less
1701 	             */
1702 	            if( (consdata->linvardecr == NULL) ||
1703 	               (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1704 	            {
1705 	               consdata->linvardecr = var;
1706 	               consdata->linvardecrcoef = coef;
1707 	            }
1708 	         }
1709 	
1710 	         if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1711 	         {
1712 	            /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1713 	             * if we have already one candidate, then take the one where the loss in the objective function is less
1714 	             */
1715 	            if( (consdata->linvarincr == NULL) ||
1716 	               (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1717 	            {
1718 	               consdata->linvarincr = var;
1719 	               consdata->linvarincrcoef = coef;
1720 	            }
1721 	         }
1722 	      }
1723 	   }
1724 	
1725 	   assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1726 	   assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1727 	
1728 	   if( consdata->linvarincr != NULL )
1729 	   {
1730 	      SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1731 	   }
1732 	   if( consdata->linvardecr != NULL )
1733 	   {
1734 	      SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1735 	   }
1736 	}
1737 	
1738 	/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1739 	 *  moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1740 	 *
1741 	 *  The method assumes that this is always possible and that not all constraints are feasible already.
1742 	 */
1743 	static
1744 	SCIP_RETCODE proposeFeasibleSolution(
1745 	   SCIP*                 scip,               /**< SCIP data structure */
1746 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1747 	   SCIP_CONS**           conss,              /**< constraints to process */
1748 	   int                   nconss,             /**< number of constraints */
1749 	   SCIP_SOL*             sol,                /**< solution to process */
1750 	   SCIP_Bool*            success             /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1751 	   )
1752 	{
1753 	   SCIP_CONSHDLRDATA* conshdlrdata;
1754 	   SCIP_SOL* newsol;
1755 	   int c;
1756 	
1757 	   assert(scip  != NULL);
1758 	   assert(conshdlr != NULL);
1759 	   assert(conss != NULL || nconss == 0);
1760 	   assert(success != NULL);
1761 	
1762 	   *success = FALSE;
1763 	
1764 	   /* don't propose new solutions if not in presolve or solving */
1765 	   if( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE || SCIPgetStage(scip) >= SCIP_STAGE_SOLVED )
1766 	      return SCIP_OKAY;
1767 	
1768 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1769 	   assert(conshdlrdata != NULL);
1770 	
1771 	   if( sol != NULL )
1772 	   {
1773 	      SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1774 	   }
1775 	   else
1776 	   {
1777 	      SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1778 	   }
1779 	   SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1780 	   SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1781 	      sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1782 	
1783 	   for( c = 0; c < nconss; ++c )
1784 	   {
1785 	      SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
1786 	      SCIP_Real viol = 0.0;
1787 	      SCIP_Real delta;
1788 	      SCIP_Real gap;
1789 	
1790 	      assert(consdata != NULL);
1791 	
1792 	      /* get absolute violation and sign */
1793 	      if( consdata->lhsviol > SCIPfeastol(scip) )
1794 	         viol = consdata->lhsviol; /* lhs - activity */
1795 	      else if( consdata->rhsviol > SCIPfeastol(scip) )
1796 	         viol = -consdata->rhsviol; /* rhs - activity */
1797 	      else
1798 	         continue; /* constraint is satisfied */
1799 	
1800 	      if( consdata->linvarincr != NULL &&
1801 	         ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1802 	      {
1803 	         SCIP_VAR* var = consdata->linvarincr;
1804 	
1805 	         /* compute how much we would like to increase var */
1806 	         delta = viol / consdata->linvarincrcoef;
1807 	         assert(delta > 0.0);
1808 	
1809 	         /* if var has an upper bound, may need to reduce delta */
1810 	         if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1811 	         {
1812 	            gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1813 	            delta = MIN(MAX(0.0, gap), delta);
1814 	         }
1815 	         if( SCIPisPositive(scip, delta) )
1816 	         {
1817 	            /* if variable is integral, round delta up so that it will still have an integer value */
1818 	            if( SCIPvarIsIntegral(var) )
1819 	               delta = SCIPceil(scip, delta);
1820 	
1821 	            SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1822 	            SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1823 	               SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));  /*lint !e613*/
1824 	
1825 	            /* adjust constraint violation, if satisfied go on to next constraint */
1826 	            viol -= consdata->linvarincrcoef * delta;
1827 	            if( SCIPisZero(scip, viol) )
1828 	               continue;
1829 	         }
1830 	      }
1831 	
1832 	      assert(viol != 0.0);
1833 	      if( consdata->linvardecr != NULL &&
1834 	         ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1835 	      {
1836 	         SCIP_VAR* var = consdata->linvardecr;
1837 	
1838 	         /* compute how much we would like to decrease var */
1839 	         delta = viol / consdata->linvardecrcoef;
1840 	         assert(delta < 0.0);
1841 	
1842 	         /* if var has a lower bound, may need to reduce delta */
1843 	         if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
1844 	         {
1845 	            gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1846 	            delta = MAX(MIN(0.0, gap), delta);
1847 	         }
1848 	         if( SCIPisNegative(scip, delta) )
1849 	         {
1850 	            /* if variable is integral, round delta down so that it will still have an integer value */
1851 	            if( SCIPvarIsIntegral(var) )
1852 	               delta = SCIPfloor(scip, delta);
1853 	            SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1854 	            /*lint --e{613} */
1855 	            SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1856 	               SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1857 	
1858 	            /* adjust constraint violation, if satisfied go on to next constraint */
1859 	            viol -= consdata->linvardecrcoef * delta;
1860 	            if( SCIPisZero(scip, viol) )
1861 	               continue;
1862 	         }
1863 	      }
1864 	
1865 	      /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1866 	      break;
1867 	   }
1868 	
1869 	   /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1870 	    * then pass it to the trysol heuristic
1871 	    */
1872 	   if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1873 	   {
1874 	      SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1875 	
1876 	      assert(conshdlrdata->trysolheur != NULL);
1877 	      SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1878 	
1879 	      *success = TRUE;
1880 	   }
1881 	
1882 	   SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1883 	
1884 	   return SCIP_OKAY;
1885 	}
1886 	
1887 	/** adds globally valid tight estimators in a given solution as cut to cutpool
1888 	 *
1889 	 * Called by addTightEstimatorCuts() for a specific expression, nlhdlr, and estimate-direction (over or under).
1890 	 */
1891 	static
1892 	SCIP_RETCODE addTightEstimatorCut(
1893 	   SCIP*                 scip,               /**< SCIP data structure */
1894 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1895 	   SCIP_CONS*            cons,               /**< constraint */
1896 	   SCIP_EXPR*            expr,               /**< expression */
1897 	   EXPRENFO*             exprenfo,           /**< expression enfo data, e.g., nlhdlr to use */
1898 	   SCIP_SOL*             sol,                /**< reference point where to estimate */
1899 	   SCIP_Bool             overestimate,       /**< whether to overestimate */
1900 	   SCIP_PTRARRAY*        rowpreps            /**< array for rowpreps */
1901 	   )
1902 	{
1903 	   SCIP_Bool estimatesuccess = FALSE;
1904 	   SCIP_Bool branchscoresuccess = FALSE;
1905 	   int minidx;
1906 	   int maxidx;
1907 	   int r;
1908 	
1909 	   assert(scip != NULL);
1910 	   assert(expr != NULL);
1911 	   assert(exprenfo != NULL);
1912 	   assert(rowpreps != NULL);
1913 	
1914 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   %sestimate using nlhdlr <%s> for expr %p (%s)\n",
1915 	      overestimate ? "over" : "under", SCIPnlhdlrGetName(exprenfo->nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))); )
1916 	
1917 	   SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, exprenfo->nlhdlr, expr, exprenfo->nlhdlrexprdata, sol,
1918 	      exprenfo->auxvalue, overestimate, SCIPinfinity(scip), FALSE, rowpreps, &estimatesuccess, &branchscoresuccess) );
1919 	
1920 	   minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
1921 	   maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
1922 	   assert(estimatesuccess == (minidx <= maxidx));
1923 	
1924 	   if( !estimatesuccess )
1925 	   {
1926 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s failed\n", SCIPnlhdlrGetName(exprenfo->nlhdlr)); )
1927 	      return SCIP_OKAY;
1928 	   }
1929 	
1930 	   for( r = minidx; r <= maxidx; ++r )
1931 	   {
1932 	      SCIP_ROWPREP* rowprep;
1933 	      SCIP_ROW* row;
1934 	      SCIP_Real estimateval;
1935 	      int i;
1936 	
1937 	      rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
1938 	      assert(rowprep != NULL);
1939 	      assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
1940 	
1941 	      /* if estimators is only local valid, then skip */
1942 	      if( SCIProwprepIsLocal(rowprep) )
1943 	      {
1944 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    skip local estimator\n"); )
1945 	         SCIPfreeRowprep(scip, &rowprep);
1946 	         continue;
1947 	      }
1948 	
1949 	      /* compute value of estimator */
1950 	      estimateval = -SCIProwprepGetSide(rowprep);
1951 	      for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
1952 	         estimateval += SCIProwprepGetCoefs(rowprep)[i] * SCIPgetSolVal(scip, sol, SCIProwprepGetVars(rowprep)[i]);
1953 	
1954 	      /* if estimator value is not tight (or even "more than tight", e.g., when estimating in integer vars), then skip */
1955 	      if( (overestimate && !SCIPisFeasLE(scip, estimateval, SCIPexprGetEvalValue(expr))) ||
1956 	         (!overestimate && !SCIPisFeasGE(scip, estimateval, SCIPexprGetEvalValue(expr))) )
1957 	      {
1958 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    skip non-tight estimator with value %g, expr value %g\n", estimateval, SCIPexprGetEvalValue(expr)); )
1959 	         SCIPfreeRowprep(scip, &rowprep);
1960 	         continue;
1961 	      }
1962 	
1963 	      /* complete estimator to cut and clean it up */
1964 	      SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
1965 	      SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPinfinity(scip), &estimatesuccess) );
1966 	
1967 	      /* if cleanup failed or rowprep is local now, then skip */
1968 	      if( !estimatesuccess || SCIProwprepIsLocal(rowprep) )
1969 	      {
1970 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    skip after cleanup failed or made estimator locally valid\n"); )
1971 	         SCIPfreeRowprep(scip, &rowprep);
1972 	         continue;
1973 	      }
1974 	
1975 	      /* generate row and add to cutpool */
1976 	      SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
1977 	
1978 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    adding cut ");
1979 	      SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
1980 	
1981 	      SCIP_CALL( SCIPaddPoolCut(scip, row) );
1982 	      /* SCIPnlhdlrIncrementNSeparated(nlhdlr); */
1983 	
1984 	      SCIP_CALL( SCIPreleaseRow(scip, &row) );
1985 	      SCIPfreeRowprep(scip, &rowprep);
1986 	   }
1987 	
1988 	   SCIP_CALL( SCIPclearPtrarray(scip, rowpreps) );
1989 	
1990 	   return SCIP_OKAY;
1991 	}
1992 	
1993 	/** adds globally valid tight estimators in a given solution as cuts to cutpool
1994 	 *
1995 	 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1996 	 * For convex constraints, we would achieve this by linearizing.
1997 	 * To avoid checking explicitly for convexity, we compute estimators via any nlhdlr that didn't say it would
1998 	 * use bound information and check whether the estimator is tight.
1999 	 *
2000 	 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
2001 	 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
2002 	 */
2003 	static
2004 	SCIP_RETCODE addTightEstimatorCuts(
2005 	   SCIP*                 scip,               /**< SCIP data structure */
2006 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2007 	   SCIP_CONS**           conss,              /**< constraints */
2008 	   int                   nconss,             /**< number of constraints */
2009 	   SCIP_SOL*             sol                 /**< reference point where to estimate */
2010 	   )
2011 	{
2012 	   SCIP_CONSDATA* consdata;
2013 	   SCIP_Longint soltag;
2014 	   SCIP_EXPRITER* it;
2015 	   SCIP_EXPR* expr;
2016 	   SCIP_PTRARRAY* rowpreps;
2017 	   int c, e;
2018 	
2019 	   assert(scip != NULL);
2020 	   assert(conshdlr != NULL);
2021 	   assert(conss != NULL || nconss == 0);
2022 	
2023 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "add tight estimators in new solution from <%s> to cutpool\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
2024 	
2025 	   /* TODO probably we just evaluated all expressions when checking the sol before it was added
2026 	    * would be nice to recognize this and skip reevaluating
2027 	    */
2028 	   soltag = SCIPgetExprNewSoltag(scip);
2029 	
2030 	   SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
2031 	
2032 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2033 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
2034 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_LEAVEEXPR);
2035 	
2036 	   for( c = 0; c < nconss; ++c )
2037 	   {
2038 	      /* skip constraints that are not enabled or deleted or have separation disabled */
2039 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2040 	         continue;
2041 	      assert(SCIPconsIsActive(conss[c]));
2042 	
2043 	      consdata = SCIPconsGetData(conss[c]);
2044 	      assert(consdata != NULL);
2045 	
2046 	      /* TODO we could remember for which constraints there is a chance that we would add anything,
2047 	       * i.e., there is some convex-like expression, and skip other constraints
2048 	       */
2049 	
2050 	      ENFOLOG(
2051 	      {
2052 	         int i;
2053 	         SCIPinfoMessage(scip, enfologfile, " constraint ");
2054 	         SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2055 	         SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2056 	         for( i = 0; i < consdata->nvarexprs; ++i )
2057 	         {
2058 	            SCIP_VAR* var;
2059 	            var = SCIPgetVarExprVar(consdata->varexprs[i]);
2060 	            SCIPinfoMessage(scip, enfologfile, "  %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2061 	                  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2062 	         }
2063 	      })
2064 	
2065 	      SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2066 	      assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2067 	
2068 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2069 	      {
2070 	         SCIP_EXPR_OWNERDATA* ownerdata;
2071 	
2072 	         ownerdata = SCIPexprGetOwnerData(expr);
2073 	         assert(ownerdata != NULL);
2074 	
2075 	         /* we can only generate a cut from an estimator if there is an auxvar */
2076 	         if( ownerdata->auxvar == NULL )
2077 	            continue;
2078 	
2079 	         /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2080 	         assert(SCIPexprGetEvalTag(expr) == soltag);
2081 	         assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2082 	         SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2083 	
2084 	         /* generate cuts from estimators of each nonlinear handler that provides estimates */
2085 	         for( e = 0; e < ownerdata->nenfos; ++e )
2086 	         {
2087 	            SCIP_NLHDLR* nlhdlr;
2088 	
2089 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
2090 	            assert(nlhdlr != NULL);
2091 	
2092 	            /* skip nlhdlr that does not implement estimate (so it does enfo) */
2093 	            if( !SCIPnlhdlrHasEstimate(nlhdlr) )
2094 	               continue;
2095 	
2096 	            /* skip nlhdlr that does not participate in separation or looks like it would give only locally-valid estimators
2097 	             * (because it uses activities on vars/auxvars)
2098 	             */
2099 	            if( ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 || ownerdata->enfos[e]->sepaaboveusesactivity) &&
2100 	                ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 || ownerdata->enfos[e]->sepabelowusesactivity) )
2101 	               continue;
2102 	
2103 	            /* skip nlhdlr_default on sum, as the estimator doesn't depend on the reference point (expr is linear in auxvars) */
2104 	            if( SCIPisExprSum(scip, expr) && strcmp(SCIPnlhdlrGetName(nlhdlr), "default") == 0 )
2105 	               continue;
2106 	
2107 	            /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables, since some nlhdlr expect this before their estimate is called */
2108 	            SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
2109 	            ENFOLOG(
2110 	               SCIPinfoMessage(scip, enfologfile, "  expr ");
2111 	               SCIPprintExpr(scip, expr, enfologfile);
2112 	               SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g, nlhdlr <%s> auxvalue: %.15g\n",
2113 	                  (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar), SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
2114 	            )
2115 	            /* due to setting values of auxvars to expr values in sol, the auxvalue should equal to expr evalvalue */
2116 	            assert(SCIPisEQ(scip, ownerdata->enfos[e]->auxvalue, SCIPexprGetEvalValue(expr)));
2117 	
2118 	            /* if nlhdlr wants to be called for overestimate and does not use local bounds, then call estimate of nlhdlr */
2119 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) && !ownerdata->enfos[e]->sepaaboveusesactivity )
2120 	            {
2121 	               SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, TRUE, rowpreps) );
2122 	            }
2123 	
2124 	            /* if nlhdlr wants to be called for underestimate and does not use local bounds, then call estimate of nlhdlr */
2125 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) && !ownerdata->enfos[e]->sepabelowusesactivity )
2126 	            {
2127 	               SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, FALSE, rowpreps) );
2128 	            }
2129 	         }
2130 	      }
2131 	   }
2132 	
2133 	   SCIPfreeExpriter(&it);
2134 	   SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
2135 	
2136 	   return SCIP_OKAY;
2137 	}
2138 	
2139 	/** processes the event that a new primal solution has been found */
2140 	static
2141 	SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2142 	{
2143 	   SCIP_CONSHDLR* conshdlr;
2144 	   SCIP_CONSHDLRDATA* conshdlrdata;
2145 	   SCIP_SOL* sol;
2146 	
2147 	   assert(scip != NULL);
2148 	   assert(event != NULL);
2149 	   assert(eventdata != NULL);
2150 	   assert(eventhdlr != NULL);
2151 	   assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND);
2152 	
2153 	   conshdlr = (SCIP_CONSHDLR*)eventdata;
2154 	
2155 	   if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2156 	      return SCIP_OKAY;
2157 	
2158 	   sol = SCIPeventGetSol(event);
2159 	   assert(sol != NULL);
2160 	
2161 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2162 	   assert(conshdlrdata != NULL);
2163 	
2164 	   /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2165 	    * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2166 	    * from the tree, but postprocessed via proposeFeasibleSolution
2167 	    */
2168 	   if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2169 	      return SCIP_OKAY;
2170 	
2171 	   SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2172 	
2173 	   SCIP_CALL( addTightEstimatorCuts(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol) );
2174 	
2175 	   return SCIP_OKAY;
2176 	}
2177 	
2178 	/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2179 	 *
2180 	 *  The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2181 	 *  tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2182 	 *
2183 	 *  Nothing will happen if SCIP is not in presolve or solve.
2184 	 */
2185 	static
2186 	SCIP_RETCODE tightenAuxVarBounds(
2187 	   SCIP*                 scip,               /**< SCIP data structure */
2188 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2189 	   SCIP_EXPR*            expr,               /**< expression whose auxvar is to be tightened */
2190 	   SCIP_INTERVAL         bounds,             /**< bounds to be used for tightening (must not be empty) */
2191 	   SCIP_Bool*            cutoff,             /**< buffer to store whether a cutoff was detected */
2192 	   int*                  ntightenings        /**< buffer to add the total number of tightenings, or NULL */
2193 	   )
2194 	{
2195 	   SCIP_VAR* var;
2196 	   SCIP_Bool tightenedlb;
2197 	   SCIP_Bool tightenedub;
2198 	   SCIP_Bool force;
2199 	
2200 	   assert(scip != NULL);
2201 	   assert(conshdlr != NULL);
2202 	   assert(expr != NULL);
2203 	   assert(cutoff != NULL);
2204 	
2205 	   /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2206 	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, bounds));
2207 	
2208 	   *cutoff = FALSE;
2209 	
2210 	   /* do not tighten variable in problem stage (important for unittests)
2211 	    * TODO put some kind of #ifdef UNITTEST around this
2212 	    */
2213 	   if( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE && SCIPgetStage(scip) > SCIP_STAGE_SOLVING )
2214 	      return SCIP_OKAY;
2215 	
2216 	   var = SCIPgetExprAuxVarNonlinear(expr);
2217 	   if( var == NULL )
2218 	      return SCIP_OKAY;
2219 	
2220 	   /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2221 	   force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2222 	
2223 	   /* try to tighten lower bound of (auxiliary) variable */
2224 	   SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2225 	   if( tightenedlb )
2226 	   {
2227 	      if( ntightenings != NULL )
2228 	         ++*ntightenings;
2229 	      SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2230 	   }
2231 	   if( *cutoff )
2232 	   {
2233 	      SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2234 	      return SCIP_OKAY;
2235 	   }
2236 	
2237 	   /* try to tighten upper bound of (auxiliary) variable */
2238 	   SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2239 	   if( tightenedub )
2240 	   {
2241 	      if( ntightenings != NULL )
2242 	         ++*ntightenings;
2243 	      SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2244 	   }
2245 	   if( *cutoff )
2246 	   {
2247 	      SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2248 	      return SCIP_OKAY;
2249 	   }
2250 	
2251 	   /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2252 	    * that seems unnecessary and we could easily undo this here, e.g.,
2253 	    * if( tightenedlb ) expr->activity.inf = bounds.inf
2254 	    */
2255 	
2256 	   return SCIP_OKAY;
2257 	}
2258 	
2259 	/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2260 	 *  and tries to tighten the bounds of the auxiliary variables accordingly
2261 	 */
2262 	static
2263 	SCIP_RETCODE forwardPropExpr(
2264 	   SCIP*                 scip,               /**< SCIP data structure */
2265 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2266 	   SCIP_EXPR*            rootexpr,           /**< expression */
2267 	   SCIP_Bool             tightenauxvars,     /**< should the bounds of auxiliary variables be tightened? */
2268 	   SCIP_Bool*            infeasible,         /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2269 	   int*                  ntightenings        /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2270 	   )
2271 	{
2272 	   SCIP_EXPRITER* it;
2273 	   SCIP_EXPR* expr;
2274 	   SCIP_EXPR_OWNERDATA* ownerdata;
2275 	   SCIP_CONSHDLRDATA* conshdlrdata;
2276 	
2277 	   assert(scip != NULL);
2278 	   assert(rootexpr != NULL);
2279 	
2280 	   if( infeasible != NULL )
2281 	      *infeasible = FALSE;
2282 	   if( ntightenings != NULL )
2283 	      *ntightenings = 0;
2284 	
2285 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2286 	   assert(conshdlrdata != NULL);
2287 	
2288 	   /* if value is valid and empty, then we cannot improve, so do nothing */
2289 	   if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2290 	   {
2291 	      SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2292 	
2293 	      if( infeasible != NULL )
2294 	         *infeasible = TRUE;
2295 	
2296 	      /* just update tag to curboundstag */
2297 	      SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2298 	
2299 	      return SCIP_OKAY;
2300 	   }
2301 	
2302 	   /* if value is up-to-date, then nothing to do */
2303 	   if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2304 	   {
2305 	      SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2306 	
2307 	      assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2308 	
2309 	      return SCIP_OKAY;
2310 	   }
2311 	
2312 	   ownerdata = SCIPexprGetOwnerData(rootexpr);
2313 	   assert(ownerdata != NULL);
2314 	
2315 	   /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2316 	    * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2317 	    * during detect, we are in some in-between state where we may want to eval activity
2318 	    * on exprs that we did not notify about their activity usage
2319 	    */
2320 	   if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2321 	   {
2322 	#ifdef DEBUG_PROP
2323 	      SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2324 	#endif
2325 	      SCIPABORT();
2326 	      return SCIP_OKAY;
2327 	   }
2328 	
2329 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2330 	   SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2331 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
2332 	
2333 	   for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it);  )
2334 	   {
2335 	      switch( SCIPexpriterGetStageDFS(it) )
2336 	      {
2337 	         case SCIP_EXPRITER_VISITINGCHILD :
2338 	         {
2339 	            /* skip child if it has been evaluated already */
2340 	            SCIP_EXPR* child;
2341 	
2342 	            child = SCIPexpriterGetChildExprDFS(it);
2343 	            if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2344 	            {
2345 	               if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2346 	                  *infeasible = TRUE;
2347 	
2348 	               expr = SCIPexpriterSkipDFS(it);
2349 	               continue;
2350 	            }
2351 	
2352 	            break;
2353 	         }
2354 	
2355 	         case SCIP_EXPRITER_LEAVEEXPR :
2356 	         {
2357 	            SCIP_INTERVAL activity;
2358 	
2359 	            /* we should not have entered this expression if its activity was already up to date */
2360 	            assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2361 	
2362 	            ownerdata = SCIPexprGetOwnerData(expr);
2363 	            assert(ownerdata != NULL);
2364 	
2365 	            /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2366 	             * so we can assume that the activity is up to date for all these variables
2367 	             * UNLESS we changed the method used to evaluate activity of variable expressions
2368 	             *   or we currently use global bounds (varevents are catched for local bound changes only)
2369 	             */
2370 	            if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2371 	                SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2372 	            {
2373 	#ifndef NDEBUG
2374 	               SCIP_INTERVAL exprhdlrinterval;
2375 	
2376 	               SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2377 	               assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2378 	               assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2379 	#endif
2380 	#ifdef DEBUG_PROP
2381 	               SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2382 	#endif
2383 	               SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2384 	
2385 	               break;
2386 	            }
2387 	
2388 	            if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2389 	            {
2390 	               /* start with entire activity if current one is invalid */
2391 	               SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
2392 	            }
2393 	            else if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)) )
2394 	            {
2395 	               /* If already empty, then don't try to compute even better activity.
2396 	                * If cons_nonlinear were alone, then we should have noted that we are infeasible
2397 	                * so an assert(infeasible == NULL || *infeasible) should work here.
2398 	                * However, after reporting a cutoff due to expr->activity being empty,
2399 	                * SCIP may wander to a different node and call propagation again.
2400 	                * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2401 	                * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2402 	                * we will still have expr->activity being empty, but will have forgotten
2403 	                * that we found infeasibility here before (!2221#note_134120).
2404 	                * Therefore we just set *infeasibility=TRUE here and stop.
2405 	                */
2406 	               if( infeasible != NULL )
2407 	                  *infeasible = TRUE;
2408 	               SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2409 	               break;
2410 	            }
2411 	            else
2412 	            {
2413 	               /* start with current activity, since it is valid */
2414 	               activity = SCIPexprGetActivity(expr);
2415 	            }
2416 	
2417 	            /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2418 	            if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2419 	            {
2420 	#ifdef DEBUG_PROP
2421 	               SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2422 	#endif
2423 	               break;
2424 	            }
2425 	
2426 	#ifdef DEBUG_PROP
2427 	            SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2428 	            SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2429 	            SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2430 	#endif
2431 	
2432 	            /* run interval eval of nonlinear handlers or expression handler */
2433 	            if( ownerdata->nenfos > 0 )
2434 	            {
2435 	               SCIP_NLHDLR* nlhdlr;
2436 	               SCIP_INTERVAL nlhdlrinterval;
2437 	               int e;
2438 	
2439 	               /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2440 	               for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2441 	               {
2442 	                  /* skip nlhdlr if it does not want to participate in activity computation */
2443 	                  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2444 	                     continue;
2445 	
2446 	                  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2447 	                  assert(nlhdlr != NULL);
2448 	
2449 	                  /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2450 	                  if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2451 	                     continue;
2452 	
2453 	                  /* let nlhdlr evaluate current expression */
2454 	                  nlhdlrinterval = activity;
2455 	                  SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2456 	                     &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2457 	#ifdef DEBUG_PROP
2458 	                  SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2459 	#endif
2460 	
2461 	                  /* update activity by intersecting with computed activity */
2462 	                  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2463 	#ifdef DEBUG_PROP
2464 	                  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2465 	#endif
2466 	               }
2467 	            }
2468 	            else
2469 	            {
2470 	               /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2471 	               SCIP_INTERVAL exprhdlrinterval = activity;
2472 	               SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2473 	#ifdef DEBUG_PROP
2474 	               SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2475 	#endif
2476 	
2477 	               /* update expr->activity by intersecting with computed activity */
2478 	               SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2479 	#ifdef DEBUG_PROP
2480 	               SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2481 	#endif
2482 	            }
2483 	
2484 	            /* if expression is integral, then we try to tighten the interval bounds a bit
2485 	             * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2486 	             * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2487 	             * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2488 	             * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2489 	             * (constants should be ok, too)
2490 	             */
2491 	            if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2492 	            {
2493 	               if( activity.inf > -SCIP_INTERVAL_INFINITY )
2494 	                  activity.inf = SCIPceil(scip, activity.inf);
2495 	               if( activity.sup <  SCIP_INTERVAL_INFINITY )
2496 	                  activity.sup = SCIPfloor(scip, activity.sup);
2497 	#ifdef DEBUG_PROP
2498 	               SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2499 	#endif
2500 	            }
2501 	
2502 	            /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2503 	             * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2504 	             */
2505 	            if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2506 	            {
2507 	               SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2508 	               SCIPintervalSetEmpty(&activity);
2509 	            }
2510 	
2511 	            /* now finally store activity in expr */
2512 	            SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2513 	
2514 	            if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity) )
2515 	            {
2516 	               if( infeasible != NULL )
2517 	                  *infeasible = TRUE;
2518 	            }
2519 	            else if( tightenauxvars && ownerdata->auxvar != NULL )
2520 	            {
2521 	               SCIP_Bool tighteninfeasible;
2522 	
2523 	               SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2524 	               if( tighteninfeasible )
2525 	               {
2526 	                  if( infeasible != NULL )
2527 	                     *infeasible = TRUE;
2528 	                  SCIPintervalSetEmpty(&activity);
2529 	                  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2530 	               }
2531 	            }
2532 	
2533 	            break;
2534 	         }
2535 	
2536 	         default:
2537 	            /* you should never be here */
2538 	            SCIPerrorMessage("unexpected iterator stage\n");
2539 	            SCIPABORT();
2540 	            break;
2541 	      }
2542 	
2543 	      expr = SCIPexpriterGetNext(it);
2544 	   }
2545 	
2546 	   SCIPfreeExpriter(&it);
2547 	
2548 	   return SCIP_OKAY;
2549 	}
2550 	
2551 	/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2552 	 *
2553 	 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2554 	 *
2555 	 * If `subsetsufficient` is FALSE, then we require
2556 	 *  - a change from an unbounded interval to a bounded one, or
2557 	 *  - or a change from an unfixed (width > epsilon) to a fixed interval, or
2558 	 *  - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2559 	 */
2560 	static
2561 	SCIP_Bool isIntervalBetter(
2562 	   SCIP*                 scip,               /**< SCIP data structure */
2563 	   SCIP_Bool             subsetsufficient,   /**< whether the intersection being a proper subset of oldinterval is sufficient */
2564 	   SCIP_INTERVAL         newinterval,        /**< new interval */
2565 	   SCIP_INTERVAL         oldinterval         /**< old interval */
2566 	   )
2567 	{
2568 	   assert(scip != NULL);
2569 	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2570 	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2571 	
2572 	   if( subsetsufficient )
2573 	      /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2574 	      return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2575 	
2576 	   /* check whether lower bound of interval becomes finite */
2577 	   if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2578 	      return TRUE;
2579 	
2580 	   /* check whether upper bound of interval becomes finite */
2581 	   if( oldinterval.sup >=  SCIP_INTERVAL_INFINITY && newinterval.sup >  SCIP_INTERVAL_INFINITY )
2582 	      return TRUE;
2583 	
2584 	   /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2585 	   if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2586 	      return TRUE;
2587 	
2588 	   /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2589 	   if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2590 	      return TRUE;
2591 	
2592 	   /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2593 	   if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2594 	      return TRUE;
2595 	
2596 	   return FALSE;
2597 	}
2598 	
2599 	/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2600 	 *
2601 	 *  The expression will be traversed in breadth first search by using this queue.
2602 	 *
2603 	 *  @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2604 	 *  forwardPropExpr() before calling this function.
2605 	 *
2606 	 *  @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2607 	 */
2608 	static
2609 	SCIP_RETCODE reversePropQueue(
2610 	   SCIP*                 scip,               /**< SCIP data structure */
2611 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2612 	   SCIP_Bool*            infeasible,         /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2613 	   int*                  ntightenings        /**< buffer to store the number of (variable) tightenings */
2614 	   )
2615 	{
2616 	   SCIP_CONSHDLRDATA* conshdlrdata;
2617 	   SCIP_EXPR* expr;
2618 	   SCIP_EXPR_OWNERDATA* ownerdata;
2619 	
2620 	   assert(infeasible != NULL);
2621 	   assert(ntightenings != NULL);
2622 	
2623 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2624 	   assert(conshdlrdata != NULL);
2625 	
2626 	   *ntightenings = 0;
2627 	
2628 	   /* main loop that calls reverse propagation for expressions on the queue
2629 	    * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2630 	    */
2631 	   while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2632 	   {
2633 	      SCIP_INTERVAL propbounds;
2634 	      int e;
2635 	
2636 	      expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2637 	      assert(expr != NULL);
2638 	
2639 	      ownerdata = SCIPexprGetOwnerData(expr);
2640 	      assert(ownerdata != NULL);
2641 	
2642 	      assert(ownerdata->inpropqueue);
2643 	      /* mark that the expression is not in the queue anymore */
2644 	      ownerdata->inpropqueue = FALSE;
2645 	
2646 	      /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2647 	       * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2648 	       */
2649 	      assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2650 	      assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2651 	      assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2652 	
2653 	      /* this intersects propbounds with activity and auxvar bounds
2654 	       * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2655 	       * auxvar bounds separately, so disabling this for now
2656 	       */
2657 	#ifdef SCIP_DISABLED_CODE
2658 	      propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2659 	      if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, propbounds) )
2660 	      {
2661 	         *infeasible = TRUE;
2662 	         break;
2663 	      }
2664 	#else
2665 	      propbounds = ownerdata->propbounds;
2666 	#endif
2667 	
2668 	      if( ownerdata->nenfos > 0 )
2669 	      {
2670 	         /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2671 	         for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2672 	         {
2673 	            SCIP_NLHDLR* nlhdlr;
2674 	            int nreds;
2675 	
2676 	            /* skip nlhdlr if it does not want to participate in activity computation */
2677 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2678 	               continue;
2679 	
2680 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
2681 	            assert(nlhdlr != NULL);
2682 	
2683 	            /* call the reverseprop of the nlhdlr */
2684 	#ifdef SCIP_DEBUG
2685 	            SCIPdebugMsg(scip, "call reverse propagation for ");
2686 	            SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2687 	            SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2688 	#endif
2689 	
2690 	            nreds = 0;
2691 	            SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2692 	            assert(nreds >= 0);
2693 	            *ntightenings += nreds;
2694 	         }
2695 	      }
2696 	      else if( SCIPexprhdlrHasReverseProp(SCIPexprGetHdlr(expr)) )
2697 	      {
2698 	         /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2699 	         SCIP_INTERVAL* childrenbounds;
2700 	         int c;
2701 	
2702 	#ifdef SCIP_DEBUG
2703 	         SCIPdebugMsg(scip, "call reverse propagation for ");
2704 	         SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2705 	         SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2706 	#endif
2707 	
2708 	         /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2709 	          * been initialized in detectNlhdlr yet (nenfos < 0)
2710 	          */
2711 	         assert(ownerdata->nenfos < 0);
2712 	
2713 	         SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2714 	         for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2715 	            childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2716 	
2717 	         /* call the reverseprop of the exprhdlr */
2718 	         SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2719 	
2720 	         if( !*infeasible )
2721 	            for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2722 	            {
2723 	               SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2724 	            }
2725 	
2726 	         SCIPfreeBufferArray(scip, &childrenbounds);
2727 	      }
2728 	   }
2729 	
2730 	   /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2731 	   while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2732 	   {
2733 	      expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2734 	      assert(expr != NULL);
2735 	
2736 	      ownerdata = SCIPexprGetOwnerData(expr);
2737 	      assert(ownerdata != NULL);
2738 	
2739 	      /* mark that the expression is not in the queue anymore */
2740 	      ownerdata->inpropqueue = FALSE;
2741 	   }
2742 	
2743 	   return SCIP_OKAY;
2744 	}
2745 	
2746 	/** calls domain propagation for a given set of constraints
2747 	 *
2748 	 *  The algorithm alternates calls of forward and reverse propagation.
2749 	 *  Forward propagation ensures that activity of expressions is up to date.
2750 	 *  Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2751 	 *  [lhs,rhs] interval as starting point.
2752 	 *
2753 	 *  The propagation algorithm works as follows:
2754 	 *   1. apply forward propagation (update activities) for all constraints not marked as propagated
2755 	 *   2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2756 	 *      if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2757 	 *      provide tighter bounds
2758 	 *   3. apply reverse propagation to all collected expressions; don't explore
2759 	 *      sub-expressions which have not changed since the beginning of the propagation loop
2760 	 *   4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2761 	 *
2762 	 *  @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2763 	 *  reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2764 	 *  constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2765 	 *
2766 	 *  TODO should we distinguish between expressions where activity information is used for separation and those where not,
2767 	 *    e.g., try less to propagate on convex constraints?
2768 	 */
2769 	static
2770 	SCIP_RETCODE propConss(
2771 	   SCIP*                 scip,               /**< SCIP data structure */
2772 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2773 	   SCIP_CONS**           conss,              /**< constraints to propagate */
2774 	   int                   nconss,             /**< total number of constraints */
2775 	   SCIP_Bool             force,              /**< force tightening even if below bound strengthening tolerance */
2776 	   SCIP_RESULT*          result,             /**< pointer to store the result */
2777 	   int*                  nchgbds             /**< buffer to add the number of changed bounds */
2778 	   )
2779 	{
2780 	   SCIP_CONSHDLRDATA* conshdlrdata;
2781 	   SCIP_CONSDATA* consdata;
2782 	   SCIP_EXPR_OWNERDATA* ownerdata;
2783 	   SCIP_Bool cutoff = FALSE;
2784 	   SCIP_INTERVAL conssides;
2785 	   int ntightenings;
2786 	   int roundnr;
2787 	   SCIP_EXPRITER* revpropcollectit = NULL;
2788 	   int i;
2789 	
2790 	   assert(scip != NULL);
2791 	   assert(conshdlr != NULL);
2792 	   assert(conss != NULL);
2793 	   assert(nconss >= 0);
2794 	   assert(result != NULL);
2795 	   assert(nchgbds != NULL);
2796 	   assert(*nchgbds >= 0);
2797 	
2798 	   /* no constraints to propagate */
2799 	   if( nconss == 0 )
2800 	   {
2801 	      *result = SCIP_DIDNOTRUN;
2802 	      return SCIP_OKAY;
2803 	   }
2804 	
2805 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2806 	   assert(conshdlrdata != NULL);
2807 	   assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2808 	   assert(!conshdlrdata->globalbounds);
2809 	
2810 	   *result = SCIP_DIDNOTFIND;
2811 	   roundnr = 0;
2812 	
2813 	   /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2814 	   conshdlrdata->forceboundtightening = force;
2815 	
2816 	   /* invalidate all propbounds (probably not needed) */
2817 	   ++conshdlrdata->curpropboundstag;
2818 	
2819 	   /* create iterator that we will use if we need to look at all auxvars */
2820 	   if( conshdlrdata->propauxvars )
2821 	   {
2822 	      SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2823 	   }
2824 	
2825 	   /* main propagation loop */
2826 	   do
2827 	   {
2828 	      SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2829 	
2830 	      assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2831 	
2832 	      /* apply forward propagation (update expression activities)
2833 	       * and add promising root expressions into queue for reversepropagation
2834 	       */
2835 	      for( i = 0; i < nconss; ++i )
2836 	      {
2837 	         consdata = SCIPconsGetData(conss[i]);
2838 	         assert(consdata != NULL);
2839 	
2840 	         /* skip deleted, non-active, or propagation-disabled constraints */
2841 	         if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2842 	            continue;
2843 	
2844 	         /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2845 	          * activity didn't change
2846 	          */
2847 	         if( consdata->ispropagated )
2848 	            continue;
2849 	
2850 	         /* update activities in expression */
2851 	         SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2852 	         SCIPdebugPrintCons(scip, conss[i], NULL);
2853 	
2854 	         ntightenings = 0;
2855 	         SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2856 	         assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2857 	
2858 	         if( cutoff )
2859 	         {
2860 	            SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2861 	            *result = SCIP_CUTOFF;
2862 	            break;
2863 	         }
2864 	
2865 	         ownerdata = SCIPexprGetOwnerData(consdata->expr);
2866 	
2867 	         /* 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 */
2868 	         if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2869 	         {
2870 	            /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2871 	             *   (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2872 	             *   so taking auxvar bounds is enough)
2873 	             */
2874 	            if( ownerdata->auxvar == NULL )
2875 	            {
2876 	               /* relax sides by SCIPepsilon() and handle infinite sides */
2877 	               SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2878 	               SCIP_Real rhs = SCIPisInfinity(scip,  consdata->rhs) ?  SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2879 	               SCIPintervalSetBounds(&conssides, lhs, rhs);
2880 	            }
2881 	            else
2882 	            {
2883 	               conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2884 	            }
2885 	            SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2886 	         }
2887 	         else
2888 	         {
2889 	            /* check whether bounds of any auxvar used in constraint provides a tightening
2890 	             *   (for the root expression, bounds of auxvar are initially set to constraint sides)
2891 	             * but skip exprs that have an auxvar, but do not participate in propagation
2892 	             */
2893 	            SCIP_EXPR* expr;
2894 	
2895 	            assert(revpropcollectit != NULL);
2896 	            SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2897 	            for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2898 	            {
2899 	               ownerdata = SCIPexprGetOwnerData(expr);
2900 	               assert(ownerdata != NULL);
2901 	
2902 	               if( ownerdata->auxvar == NULL )
2903 	                  continue;
2904 	
2905 	               if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2906 	                  continue;
2907 	
2908 	               conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2909 	               SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2910 	            }
2911 	         }
2912 	
2913 	         if( cutoff )
2914 	         {
2915 	            SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2916 	            *result = SCIP_CUTOFF;
2917 	            break;
2918 	         }
2919 	
2920 	         assert(ntightenings >= 0);
2921 	         if( ntightenings > 0 )
2922 	         {
2923 	            *nchgbds += ntightenings;
2924 	            *result = SCIP_REDUCEDDOM;
2925 	         }
2926 	
2927 	         /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2928 	         consdata->ispropagated = TRUE;
2929 	      }
2930 	
2931 	      /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2932 	      SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2933 	      assert(ntightenings >= 0);
2934 	      assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2935 	
2936 	      if( cutoff )
2937 	      {
2938 	         SCIPdebugMsg(scip, " -> cutoff\n");
2939 	         *result = SCIP_CUTOFF;
2940 	         break;
2941 	      }
2942 	
2943 	      if( ntightenings > 0 )
2944 	      {
2945 	         *nchgbds += ntightenings;
2946 	         *result = SCIP_REDUCEDDOM;
2947 	      }
2948 	   }
2949 	   while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2950 	
2951 	   if( conshdlrdata->propauxvars )
2952 	   {
2953 	      SCIPfreeExpriter(&revpropcollectit);
2954 	   }
2955 	
2956 	   conshdlrdata->forceboundtightening = FALSE;
2957 	
2958 	   /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2959 	   ++conshdlrdata->curpropboundstag;
2960 	
2961 	   return SCIP_OKAY;
2962 	}
2963 	
2964 	/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2965 	 *
2966 	 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2967 	 *
2968 	 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2969 	 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2970 	 */
2971 	static
2972 	SCIP_RETCODE propExprDomains(
2973 	   SCIP*                 scip,               /**< SCIP data structure */
2974 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2975 	   SCIP_CONS**           conss,              /**< constraints to propagate */
2976 	   int                   nconss,             /**< total number of constraints */
2977 	   SCIP_RESULT*          result,             /**< pointer to store the result */
2978 	   int*                  nchgbds             /**< buffer to add the number of changed bounds */
2979 	   )
2980 	{
2981 	   SCIP_CONSDATA* consdata;
2982 	   SCIP_EXPRITER* it;
2983 	   SCIP_EXPR* expr;
2984 	   SCIP_EXPR_OWNERDATA* ownerdata;
2985 	   SCIP_Bool cutoff = FALSE;
2986 	   int ntightenings;
2987 	   int c;
2988 	   int e;
2989 	
2990 	   assert(scip != NULL);
2991 	   assert(conshdlr != NULL);
2992 	   assert(conss != NULL);
2993 	   assert(nconss >= 0);
2994 	   assert(result != NULL);
2995 	   assert(nchgbds != NULL);
2996 	   assert(*nchgbds >= 0);
2997 	
2998 	   assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
2999 	   assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
3000 	   assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
3001 	
3002 	   *result = SCIP_DIDNOTFIND;
3003 	
3004 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3005 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
3006 	
3007 	   for( c = 0; c < nconss && !cutoff; ++c )
3008 	   {
3009 	      /* skip deleted, non-active, or propagation-disabled constraints */
3010 	      if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
3011 	         continue;
3012 	
3013 	      consdata = SCIPconsGetData(conss[c]);
3014 	      assert(consdata != NULL);
3015 	
3016 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
3017 	      {
3018 	         ownerdata = SCIPexprGetOwnerData(expr);
3019 	         assert(ownerdata != NULL);
3020 	
3021 	         /* call reverseprop for those nlhdlr that participate in this expr's activity computation
3022 	          * this will propagate the current activity
3023 	          */
3024 	         for( e = 0; e < ownerdata->nenfos; ++e )
3025 	         {
3026 	            SCIP_NLHDLR* nlhdlr;
3027 	            assert(ownerdata->enfos[e] != NULL);
3028 	
3029 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
3030 	            assert(nlhdlr != NULL);
3031 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
3032 	               continue;
3033 	
3034 	            SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
3035 	                  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
3036 	            ntightenings = 0;
3037 	            SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
3038 	                    SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
3039 	
3040 	            if( cutoff )
3041 	            {
3042 	               /* stop everything if we detected infeasibility */
3043 	               SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3044 	               *result = SCIP_CUTOFF;
3045 	               break;
3046 	            }
3047 	
3048 	            assert(ntightenings >= 0);
3049 	            if( ntightenings > 0 )
3050 	            {
3051 	               *nchgbds += ntightenings;
3052 	               *result = SCIP_REDUCEDDOM;
3053 	            }
3054 	         }
3055 	      }
3056 	   }
3057 	
3058 	   /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
3059 	   SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
3060 	   assert(ntightenings >= 0);
3061 	
3062 	   if( cutoff )
3063 	   {
3064 	      SCIPdebugMsg(scip, " -> cutoff\n");
3065 	      *result = SCIP_CUTOFF;
3066 	   }
3067 	   else if( ntightenings > 0 )
3068 	   {
3069 	      *nchgbds += ntightenings;
3070 	      *result = SCIP_REDUCEDDOM;
3071 	   }
3072 	
3073 	   SCIPfreeExpriter(&it);
3074 	
3075 	   /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
3076 	   ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
3077 	
3078 	   return SCIP_OKAY;
3079 	}
3080 	
3081 	/** propagates variable locks through expression and adds locks to variables */
3082 	static
3083 	SCIP_RETCODE propagateLocks(
3084 	   SCIP*                 scip,               /**< SCIP data structure */
3085 	   SCIP_EXPR*            expr,               /**< expression */
3086 	   int                   nlockspos,          /**< number of positive locks */
3087 	   int                   nlocksneg           /**< number of negative locks */
3088 	   )
3089 	{
3090 	   SCIP_EXPR_OWNERDATA* ownerdata;
3091 	   SCIP_EXPRITER* it;
3092 	   SCIP_EXPRITER_USERDATA ituserdata;
3093 	
3094 	   assert(expr != NULL);
3095 	
3096 	   /* if no locks, then nothing to propagate */
3097 	   if( nlockspos == 0 && nlocksneg == 0 )
3098 	      return SCIP_OKAY;
3099 	
3100 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3101 	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
3102 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
3103 	   assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3104 	
3105 	   /* store locks in root node */
3106 	   ituserdata.intvals[0] = nlockspos;
3107 	   ituserdata.intvals[1] = nlocksneg;
3108 	   SCIPexpriterSetCurrentUserData(it, ituserdata);
3109 	
3110 	   while( !SCIPexpriterIsEnd(it) )
3111 	   {
3112 	      /* collect locks */
3113 	      ituserdata = SCIPexpriterGetCurrentUserData(it);
3114 	      nlockspos = ituserdata.intvals[0];
3115 	      nlocksneg = ituserdata.intvals[1];
3116 	
3117 	      ownerdata = SCIPexprGetOwnerData(expr);
3118 	
3119 	      switch( SCIPexpriterGetStageDFS(it) )
3120 	      {
3121 	         case SCIP_EXPRITER_ENTEREXPR:
3122 	         {
3123 	            if( SCIPisExprVar(scip, expr) )
3124 	            {
3125 	               /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3126 	               SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3127 	            }
3128 	
3129 	            /* add locks to expression */
3130 	            ownerdata->nlockspos += nlockspos;
3131 	            ownerdata->nlocksneg += nlocksneg;
3132 	
3133 	            /* add monotonicity information if expression has been locked for the first time */
3134 	            if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3135 	               && SCIPexprhdlrHasMonotonicity(SCIPexprGetHdlr(expr)) )
3136 	            {
3137 	               int i;
3138 	
3139 	               assert(ownerdata->monotonicity == NULL);
3140 	               assert(ownerdata->monotonicitysize == 0);
3141 	
3142 	               SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3143 	               ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3144 	
3145 	               /* store the monotonicity for each child */
3146 	               for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3147 	               {
3148 	                  SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3149 	               }
3150 	            }
3151 	            break;
3152 	         }
3153 	
3154 	         case SCIP_EXPRITER_LEAVEEXPR :
3155 	         {
3156 	            /* remove monotonicity information if expression has been unlocked */
3157 	            if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3158 	            {
3159 	               assert(ownerdata->monotonicitysize > 0);
3160 	               /* keep this assert for checking whether someone changed an expression without updating locks properly */
3161 	               assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3162 	
3163 	               SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3164 	               ownerdata->monotonicitysize = 0;
3165 	            }
3166 	            break;
3167 	         }
3168 	
3169 	         case SCIP_EXPRITER_VISITINGCHILD :
3170 	         {
3171 	            SCIP_MONOTONE monotonicity;
3172 	
3173 	            /* get monotonicity of child */
3174 	            /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3175 	             * SCIPcallExprMonotonicity
3176 	             */
3177 	            monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3178 	
3179 	            /* compute resulting locks of the child expression */
3180 	            switch( monotonicity )
3181 	            {
3182 	               case SCIP_MONOTONE_INC:
3183 	                  ituserdata.intvals[0] = nlockspos;
3184 	                  ituserdata.intvals[1] = nlocksneg;
3185 	                  break;
3186 	               case SCIP_MONOTONE_DEC:
3187 	                  ituserdata.intvals[0] = nlocksneg;
3188 	                  ituserdata.intvals[1] = nlockspos;
3189 	                  break;
3190 	               case SCIP_MONOTONE_UNKNOWN:
3191 	                  ituserdata.intvals[0] = nlockspos + nlocksneg;
3192 	                  ituserdata.intvals[1] = nlockspos + nlocksneg;
3193 	                  break;
3194 	               case SCIP_MONOTONE_CONST:
3195 	                  ituserdata.intvals[0] = 0;
3196 	                  ituserdata.intvals[1] = 0;
3197 	                  break;
3198 	            }
3199 	            /* set locks in child expression */
3200 	            SCIPexpriterSetChildUserData(it, ituserdata);
3201 	
3202 	            break;
3203 	         }
3204 	
3205 	         default :
3206 	            /* you should never be here */
3207 	            SCIPABORT();
3208 	            break;
3209 	      }
3210 	
3211 	      expr = SCIPexpriterGetNext(it);
3212 	   }
3213 	
3214 	   SCIPfreeExpriter(&it);
3215 	
3216 	   return SCIP_OKAY;
3217 	}
3218 	
3219 	/** main function for adding locks to expressions and variables
3220 	 *
3221 	 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3222 	 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3223 	 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3224 	 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3225 	 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3226 	 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3227 	 * which implies that updating the monotonicity information during the next locking of this expression does not
3228 	 * break existing locks.
3229 	 *
3230 	 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3231 	 *       locks from an expression and repropagating them after the structural changes have been applied.
3232 	 *       Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3233 	 *       to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3234 	 */
3235 	static
3236 	SCIP_RETCODE addLocks(
3237 	   SCIP*                 scip,               /**< SCIP data structure */
3238 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
3239 	   int                   nlockspos,          /**< number of positive rounding locks */
3240 	   int                   nlocksneg           /**< number of negative rounding locks */
3241 	   )
3242 	{
3243 	   SCIP_CONSDATA* consdata;
3244 	
3245 	   assert(cons != NULL);
3246 	
3247 	   if( nlockspos == 0 && nlocksneg == 0 )
3248 	      return SCIP_OKAY;
3249 	
3250 	   consdata = SCIPconsGetData(cons);
3251 	   assert(consdata != NULL);
3252 	
3253 	   /* no constraint sides -> nothing to lock */
3254 	   if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3255 	      return SCIP_OKAY;
3256 	
3257 	   /* remember locks */
3258 	   consdata->nlockspos += nlockspos;
3259 	   consdata->nlocksneg += nlocksneg;
3260 	
3261 	   assert(consdata->nlockspos >= 0);
3262 	   assert(consdata->nlocksneg >= 0);
3263 	
3264 	   /* compute locks for lock propagation */
3265 	   if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3266 	   {
3267 	      SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3268 	   }
3269 	   else if( !SCIPisInfinity(scip, consdata->rhs) )
3270 	   {
3271 	      SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3272 	   }
3273 	   else
3274 	   {
3275 	      assert(!SCIPisInfinity(scip, -consdata->lhs));
3276 	      SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3277 	   }
3278 	
3279 	   return SCIP_OKAY;
3280 	}
3281 	
3282 	/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3283 	static
3284 	SCIP_RETCODE createNlRow(
3285 	   SCIP*                 scip,               /**< SCIP data structure */
3286 	   SCIP_CONS*            cons                /**< nonlinear constraint */
3287 	   )
3288 	{
3289 	   SCIP_CONSDATA* consdata;
3290 	
3291 	   assert(scip != NULL);
3292 	   assert(cons != NULL);
3293 	
3294 	   consdata = SCIPconsGetData(cons);
3295 	   assert(consdata != NULL);
3296 	   assert(consdata->expr != NULL);
3297 	
3298 	   if( consdata->nlrow != NULL )
3299 	   {
3300 	      SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3301 	   }
3302 	
3303 	   /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3304 	   SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3305 	         0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3306 	
3307 	   if( SCIPisExprSum(scip, consdata->expr) )
3308 	   {
3309 	      /* if root is a sum, then split into linear and nonlinear terms */
3310 	      SCIP_EXPR* nonlinpart;
3311 	      SCIP_EXPR* child;
3312 	      SCIP_Real* coefs;
3313 	      int i;
3314 	
3315 	      coefs = SCIPgetCoefsExprSum(consdata->expr);
3316 	
3317 	      /* constant term of sum */
3318 	      SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3319 	
3320 	      /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3321 	      SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3322 	
3323 	      for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3324 	      {
3325 	         child = SCIPexprGetChildren(consdata->expr)[i];
3326 	         if( SCIPisExprVar(scip, child) )
3327 	         {
3328 	            /* linear term */
3329 	            SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3330 	         }
3331 	         else
3332 	         {
3333 	            /* nonlinear term */
3334 	            SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3335 	         }
3336 	      }
3337 	
3338 	      if( SCIPexprGetNChildren(nonlinpart) > 0 )
3339 	      {
3340 	         /* add expression to nlrow (this will make a copy) */
3341 	         SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3342 	      }
3343 	      SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3344 	   }
3345 	   else
3346 	   {
3347 	      SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3348 	   }
3349 	
3350 	   return SCIP_OKAY;
3351 	}
3352 	
3353 	/** compares enfodata by enforcement priority of nonlinear handler
3354 	 *
3355 	 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3356 	 */
3357 	static
3358 	SCIP_DECL_SORTPTRCOMP(enfodataCmp)
3359 	{
3360 	   SCIP_NLHDLR* h1;
3361 	   SCIP_NLHDLR* h2;
3362 	
3363 	   assert(elem1 != NULL);
3364 	   assert(elem2 != NULL);
3365 	
3366 	   h1 = ((EXPRENFO*)elem1)->nlhdlr;
3367 	   h2 = ((EXPRENFO*)elem2)->nlhdlr;
3368 	
3369 	   assert(h1 != NULL);
3370 	   assert(h2 != NULL);
3371 	
3372 	   if( SCIPnlhdlrGetEnfoPriority(h1) != SCIPnlhdlrGetEnfoPriority(h2) )
3373 	      return SCIPnlhdlrGetEnfoPriority(h1) - SCIPnlhdlrGetEnfoPriority(h2);
3374 	
3375 	   if( SCIPnlhdlrGetDetectPriority(h1) != SCIPnlhdlrGetDetectPriority(h2) )
3376 	      return SCIPnlhdlrGetDetectPriority(h1) - SCIPnlhdlrGetDetectPriority(h2);
3377 	
3378 	   return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3379 	}
3380 	
3381 	/** install nlhdlrs in one expression */
3382 	static
3383 	SCIP_RETCODE detectNlhdlr(
3384 	   SCIP*                 scip,               /**< SCIP data structure */
3385 	   SCIP_EXPR*            expr,               /**< expression for which to run detection routines */
3386 	   SCIP_CONS*            cons                /**< constraint for which expr == consdata->expr, otherwise NULL */
3387 	   )
3388 	{
3389 	   SCIP_EXPR_OWNERDATA* ownerdata;
3390 	   SCIP_CONSHDLRDATA* conshdlrdata;
3391 	   SCIP_NLHDLR_METHOD enforcemethodsallowed;
3392 	   SCIP_NLHDLR_METHOD enforcemethods;
3393 	   SCIP_NLHDLR_METHOD enforcemethodsnew;
3394 	   SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3395 	   SCIP_NLHDLR_METHOD nlhdlrparticipating;
3396 	   SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3397 	   int enfossize;  /* allocated length of expr->enfos array */
3398 	   int h;
3399 	
3400 	   assert(expr != NULL);
3401 	
3402 	   ownerdata = SCIPexprGetOwnerData(expr);
3403 	   assert(ownerdata != NULL);
3404 	
3405 	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3406 	   assert(conshdlrdata != NULL);
3407 	   assert(conshdlrdata->auxvarid >= 0);
3408 	   assert(!conshdlrdata->indetect);
3409 	
3410 	   /* there should be no enforcer yet and detection should not even have considered expr yet */
3411 	   assert(ownerdata->nenfos < 0);
3412 	   assert(ownerdata->enfos == NULL);
3413 	
3414 	   /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3415 	    * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3416 	    * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3417 	    * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3418 	    * - if no one uses activity, then do not need activity methods
3419 	    */
3420 	   enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3421 	   if( ownerdata->nauxvaruses == 0 )
3422 	      enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3423 	   else
3424 	   {
3425 	      if( ownerdata->nlockspos == 0 )  /* no need for underestimation */
3426 	         enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3427 	      if( ownerdata->nlocksneg == 0 )  /* no need for overestimation */
3428 	         enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3429 	   }
3430 	   if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3431 	      enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3432 	
3433 	   /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3434 	   assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3435 	
3436 	   /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3437 	   enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3438 	
3439 	   ownerdata->nenfos = 0;
3440 	   enfossize = 2;
3441 	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3442 	   conshdlrdata->indetect = TRUE;
3443 	
3444 	   SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3445 	      cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3446 	      (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3447 	      (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3448 	      (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3449 	
3450 	   for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3451 	   {
3452 	      SCIP_NLHDLR* nlhdlr;
3453 	
3454 	      nlhdlr = conshdlrdata->nlhdlrs[h];
3455 	      assert(nlhdlr != NULL);
3456 	
3457 	      /* skip disabled nlhdlrs */
3458 	      if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3459 	         continue;
3460 	
3461 	      /* call detect routine of nlhdlr */
3462 	      nlhdlrexprdata = NULL;
3463 	      enforcemethodsnew = enforcemethods;
3464 	      nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3465 	      conshdlrdata->registerusesactivitysepabelow = FALSE;  /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3466 	      conshdlrdata->registerusesactivitysepaabove = FALSE;  /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3467 	      SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3468 	
3469 	      /* nlhdlr might have claimed more than needed: clean up sepa flags */
3470 	      nlhdlrparticipating &= enforcemethodsallowed;
3471 	
3472 	      /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3473 	      assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3474 	
3475 	      /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3476 	       * They are also cleaned up here to ensure that only the needed methods are claimed.
3477 	       */
3478 	      nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3479 	
3480 	      /* nlhdlr needs to participate for the methods it is enforcing */
3481 	      assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3482 	
3483 	      if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3484 	      {
3485 	         /* nlhdlr might not have detected anything, or all set flags might have been removed by
3486 	          * clean up; in the latter case, we may need to free nlhdlrexprdata */
3487 	
3488 	         /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3489 	         if( nlhdlrexprdata != NULL )
3490 	         {
3491 	            SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3492 	         }
3493 	         /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3494 	         assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3495 	
3496 	         SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3497 	
3498 	         continue;
3499 	      }
3500 	
3501 	      SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3502 	         SCIPnlhdlrGetName(nlhdlr),
3503 	         ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3504 	         ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3505 	         ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3506 	
3507 	      /* store nlhdlr and its data */
3508 	      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3509 	      SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3510 	      ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3511 	      ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3512 	      ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3513 	      ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3514 	      ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3515 	      ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3516 	      ownerdata->nenfos++;
3517 	
3518 	      /* update enforcement flags */
3519 	      enforcemethods = enforcemethodsnew;
3520 	   }
3521 	
3522 	   conshdlrdata->indetect = FALSE;
3523 	
3524 	   /* stop if an enforcement method is missing but we are already in solving stage
3525 	    * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3526 	    */
3527 	   if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3528 	   {
3529 	      SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3530 	      return SCIP_ERROR;
3531 	   }
3532 	
3533 	   assert(ownerdata->nenfos > 0);
3534 	
3535 	   /* sort nonlinear handlers by enforcement priority, in decreasing order */
3536 	   if( ownerdata->nenfos > 1 )
3537 	      SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3538 	
3539 	   /* resize enfos array to be nenfos long */
3540 	   SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3541 	
3542 	   return SCIP_OKAY;
3543 	}
3544 	
3545 	/** detect nlhdlrs that can handle the expressions */
3546 	static
3547 	SCIP_RETCODE detectNlhdlrs(
3548 	   SCIP*                 scip,               /**< SCIP data structure */
3549 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3550 	   SCIP_CONS**           conss,              /**< constraints for which to run nlhdlr detect */
3551 	   int                   nconss              /**< total number of constraints */
3552 	   )
3553 	{
3554 	   SCIP_CONSHDLRDATA* conshdlrdata;
3555 	   SCIP_CONSDATA* consdata;
3556 	   SCIP_EXPR* expr;
3557 	   SCIP_EXPR_OWNERDATA* ownerdata;
3558 	   SCIP_EXPRITER* it;
3559 	   int i;
3560 	
3561 	   assert(conss != NULL || nconss == 0);
3562 	   assert(nconss >= 0);
3563 	   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 */
3564 	
3565 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
3566 	   assert(conshdlrdata != NULL);
3567 	
3568 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3569 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, TRUE) );
3570 	
3571 	   if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3572 	   {
3573 	      /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3574 	       * for example, this happens if globally valid nonlinear constraints are added during the tree search
3575 	       */
3576 	      SCIPincrementCurBoundsTagNonlinear(conshdlr, TRUE);
3577 	      conshdlrdata->globalbounds = TRUE;
3578 	      conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3579 	   }
3580 	
3581 	   for( i = 0; i < nconss; ++i )
3582 	   {
3583 	      assert(conss != NULL && conss[i] != NULL);
3584 	
3585 	      consdata = SCIPconsGetData(conss[i]);
3586 	      assert(consdata != NULL);
3587 	      assert(consdata->expr != NULL);
3588 	
3589 	      /* if a constraint is separated, we currently need it to be initial, too
3590 	       * this is because INITLP will create the auxiliary variables that are used for any separation
3591 	       * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3592 	       */
3593 	      assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3594 	
3595 	      ownerdata = SCIPexprGetOwnerData(consdata->expr);
3596 	      assert(ownerdata != NULL);
3597 	
3598 	      /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3599 	       * then we would normally skip to run DETECT again
3600 	       * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3601 	       * thus, if expr is the root expression, we rerun DETECT
3602 	       */
3603 	      if( ownerdata->nenfos > 0 )
3604 	      {
3605 	         SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3606 	         assert(ownerdata->nenfos < 0);
3607 	      }
3608 	
3609 	      /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3610 	       *   this way we can treat the root expression like any other expression when enforcing via separation
3611 	       * if constraint will be propagated, then register activity usage of root expression
3612 	       * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3613 	       */
3614 	      conshdlrdata->indetect = TRUE;
3615 	      SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, consdata->expr,
3616 	         SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3617 	         SCIPconsIsPropagated(conss[i]),
3618 	         FALSE, FALSE) );
3619 	      conshdlrdata->indetect = FALSE;
3620 	
3621 	      /* compute integrality information for all subexpressions */
3622 	      SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3623 	
3624 	      /* run detectNlhdlr on all expr where required */
3625 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3626 	      {
3627 	         ownerdata = SCIPexprGetOwnerData(expr);
3628 	         assert(ownerdata != NULL);
3629 	
3630 	         /* skip exprs that we already looked at */
3631 	         if( ownerdata->nenfos >= 0 )
3632 	            continue;
3633 	
3634 	         /* if there is use of the auxvar, then someone requires that
3635 	          *   auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3636 	          *   thus, we need to find nlhdlrs that separate or estimate
3637 	          * if there is use of the activity, then there is someone requiring that
3638 	          *   activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3639 	          *   thus, we need to find nlhdlrs that do interval-evaluation
3640 	          */
3641 	         if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3642 	         {
3643 	            SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3644 	
3645 	            assert(ownerdata->nenfos >= 0);
3646 	         }
3647 	         else
3648 	         {
3649 	            /* remember that we looked at this expression during detectNlhdlrs
3650 	             * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3651 	             * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3652 	             * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3653 	             */
3654 	            ownerdata->nenfos = 0;
3655 	         }
3656 	      }
3657 	
3658 	      /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3659 	      if( SCIPconsIsPropagated(conss[i]) )
3660 	         consdata->ispropagated = FALSE;
3661 	   }
3662 	
3663 	   if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3664 	   {
3665 	      /* ensure that the local bounds are used again when reevaluating the expressions later;
3666 	       * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3667 	       */
3668 	      SCIPincrementCurBoundsTagNonlinear(conshdlr, FALSE);
3669 	      conshdlrdata->globalbounds = FALSE;
3670 	      conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3671 	   }
3672 	   else
3673 	   {
3674 	      /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3675 	      SCIPincrementCurBoundsTagNonlinear(conshdlr, FALSE);
3676 	   }
3677 	
3678 	   SCIPfreeExpriter(&it);
3679 	
3680 	   return SCIP_OKAY;
3681 	}
3682 	
3683 	/** initializes (pre)solving data of constraints
3684 	 *
3685 	 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3686 	 * not be modified.
3687 	 * In particular, this function
3688 	 * - runs the detection method of nlhldrs
3689 	 * - looks for unlocked linear variables
3690 	 * - checks curvature (if not in presolve)
3691 	 * - creates and add row to NLP (if not in presolve)
3692 	 *
3693 	 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3694 	 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3695 	 */
3696 	static
3697 	SCIP_RETCODE initSolve(
3698 	   SCIP*                 scip,               /**< SCIP data structure */
3699 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3700 	   SCIP_CONS**           conss,              /**< constraints */
3701 	   int                   nconss              /**< number of constraints */
3702 	   )
3703 	{
3704 	   int c;
3705 	
3706 	   for( c = 0; c < nconss; ++c )
3707 	   {
3708 	      /* check for a linear variable that can be increase or decreased without harming feasibility */
3709 	      findUnlockedLinearVar(scip, conss[c]);
3710 	
3711 	      if( SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3712 	      {
3713 	         SCIP_CONSDATA* consdata;
3714 	         SCIP_Bool success = FALSE;
3715 	
3716 	         consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
3717 	         assert(consdata != NULL);
3718 	         assert(consdata->expr != NULL);
3719 	
3720 	         /* call the curvature detection algorithm of the convex nonlinear handler
3721 	          * Check only for those curvature that may result in a convex inequality, i.e.,
3722 	          * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3723 	          * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3724 	          */
3725 	         if( !SCIPisInfinity(scip, -consdata->lhs) )
3726 	         {
3727 	            SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3728 	            if( success )
3729 	               consdata->curv = SCIP_EXPRCURV_CONCAVE;
3730 	         }
3731 	         if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3732 	         {
3733 	            SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3734 	            if( success )
3735 	               consdata->curv = SCIP_EXPRCURV_CONVEX;
3736 	         }
3737 	         SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3738 	
3739 	         /* add nlrow representation to NLP, if NLP had been constructed */
3740 	         if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3741 	         {
3742 	            if( consdata->nlrow == NULL )
3743 	            {
3744 	               SCIP_CALL( createNlRow(scip, conss[c]) );
3745 	               assert(consdata->nlrow != NULL);
3746 	            }
3747 	            SCIPnlrowSetCurvature(consdata->nlrow, consdata->curv);
3748 	            SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3749 	         }
3750 	      }
3751 	   }
3752 	
3753 	   /* register non linear handlers */
3754 	   SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3755 	
3756 	   return SCIP_OKAY;
3757 	}
3758 	
3759 	/** deinitializes (pre)solving data of constraints
3760 	 *
3761 	 * This removes the initialization data created in initSolve().
3762 	 *
3763 	 * This function can be called in presolve and solve.
3764 	 *
3765 	 * TODO At the moment, it should not be called for a constraint if there are other constraints
3766 	 * that use the same expressions but still require their nlhdlr.
3767 	 * We should probably only decrement the auxvar and activity usage for the root expr and then
3768 	 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3769 	 */
3770 	static
3771 	SCIP_RETCODE deinitSolve(
3772 	   SCIP*                 scip,               /**< SCIP data structure */
3773 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3774 	   SCIP_CONS**           conss,              /**< constraints */
3775 	   int                   nconss              /**< number of constraints */
3776 	   )
3777 	{
3778 	   SCIP_EXPRITER* it;
3779 	   SCIP_EXPR* expr;
3780 	   SCIP_CONSDATA* consdata;
3781 	   SCIP_Bool rootactivityvalid;
3782 	   int c;
3783 	
3784 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3785 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
3786 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_LEAVEEXPR);
3787 	
3788 	   /* call deinitialization callbacks of expression and nonlinear handlers
3789 	    * free nonlinear handlers information from expressions
3790 	    * remove auxiliary variables and nactivityuses counts from expressions
3791 	    */
3792 	   for( c = 0; c < nconss; ++c )
3793 	   {
3794 	      assert(conss != NULL);
3795 	      assert(conss[c] != NULL);
3796 	
3797 	      consdata = SCIPconsGetData(conss[c]);
3798 	      assert(consdata != NULL);
3799 	      assert(consdata->expr != NULL);
3800 	
3801 	      /* check and remember whether activity in root is valid */
3802 	      rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3803 	
3804 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3805 	      {
3806 	         SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3807 	
3808 	         /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3809 	         SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3810 	
3811 	         /* remove quadratic info */
3812 	         SCIPfreeExprQuadratic(scip, expr);
3813 	
3814 	         if( rootactivityvalid )
3815 	         {
3816 	            /* ensure activity is valid if consdata->expr activity is valid
3817 	             * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3818 	             * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3819 	             * so this childs activity would be invalid, which can generate confusion
3820 	             */
3821 	            SCIP_CALL( SCIPevalExprActivity(scip, expr) );
3822 	         }
3823 	      }
3824 	
3825 	      if( consdata->nlrow != NULL )
3826 	      {
3827 	         /* remove row from NLP, if still in solving
3828 	          * if we are in exitsolve, the whole NLP will be freed anyway
3829 	          */
3830 	         if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3831 	         {
3832 	            SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3833 	         }
3834 	
3835 	         SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3836 	      }
3837 	
3838 	      /* forget about linear variables that can be increased or decreased without harming feasibility */
3839 	      consdata->linvardecr = NULL;
3840 	      consdata->linvarincr = NULL;
3841 	
3842 	      /* forget about curvature */
3843 	      consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3844 	   }
3845 	
3846 	   SCIPfreeExpriter(&it);
3847 	
3848 	   return SCIP_OKAY;
3849 	}
3850 	
3851 	/** helper method to decide whether a given expression is product of at least two binary variables */
3852 	static
3853 	SCIP_Bool isBinaryProduct(
3854 	   SCIP*                 scip,               /**< SCIP data structure */
3855 	   SCIP_EXPR*            expr                /**< expression */
3856 	   )
3857 	{
3858 	   int i;
3859 	
3860 	   assert(expr != NULL);
3861 	
3862 	   /* check whether the expression is a product */
3863 	   if( !SCIPisExprProduct(scip, expr) )
3864 	      return FALSE;
3865 	
3866 	   /* don't consider products with a coefficient != 1 and products with a single child
3867 	    * simplification will take care of this expression later
3868 	    */
3869 	   if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3870 	      return FALSE;
3871 	
3872 	   for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3873 	   {
3874 	      SCIP_EXPR* child;
3875 	      SCIP_VAR* var;
3876 	      SCIP_Real ub;
3877 	      SCIP_Real lb;
3878 	
3879 	      child = SCIPexprGetChildren(expr)[i];
3880 	      assert(child != NULL);
3881 	
3882 	      if( !SCIPisExprVar(scip, child) )
3883 	         return FALSE;
3884 	
3885 	      var = SCIPgetVarExprVar(child);
3886 	      lb = SCIPvarGetLbLocal(var);
3887 	      ub = SCIPvarGetUbLocal(var);
3888 	
3889 	      /* check whether variable is integer and has [0,1] as variable bounds */
3890 	      if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3891 	         return FALSE;
3892 	   }
3893 	
3894 	   return TRUE;
3895 	}
3896 	
3897 	/** helper method to collect all bilinear binary product terms */
3898 	static
3899 	SCIP_RETCODE getBilinearBinaryTerms(
3900 	   SCIP*                 scip,               /**< SCIP data structure */
3901 	   SCIP_EXPR*            sumexpr,            /**< sum expression */
3902 	   SCIP_VAR**            xs,                 /**< array to collect first variable of each bilinear binary product */
3903 	   SCIP_VAR**            ys,                 /**< array to collect second variable of each bilinear binary product */
3904 	   int*                  childidxs,          /**< array to store the index of the child of each stored bilinear binary product */
3905 	   int*                  nterms              /**< pointer to store the total number of bilinear binary terms */
3906 	   )
3907 	{
3908 	   int i;
3909 	
3910 	   assert(sumexpr != NULL);
3911 	   assert(SCIPisExprSum(scip, sumexpr));
3912 	   assert(xs != NULL);
3913 	   assert(ys != NULL);
3914 	   assert(childidxs != NULL);
3915 	   assert(nterms != NULL);
3916 	
3917 	   *nterms = 0;
3918 	
3919 	   for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3920 	   {
3921 	      SCIP_EXPR* child;
3922 	
3923 	      child = SCIPexprGetChildren(sumexpr)[i];
3924 	      assert(child != NULL);
3925 	
3926 	      if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3927 	      {
3928 	         SCIP_VAR* x = SCIPgetVarExprVar(SCIPexprGetChildren(child)[0]);
3929 	         SCIP_VAR* y = SCIPgetVarExprVar(SCIPexprGetChildren(child)[1]);
3930 	
3931 	         assert(x != NULL);
3932 	         assert(y != NULL);
3933 	
3934 	         if( x != y )
3935 	         {
3936 	            xs[*nterms] = x;
3937 	            ys[*nterms] = y;
3938 	            childidxs[*nterms] = i;
3939 	            ++(*nterms);
3940 	         }
3941 	      }
3942 	   }
3943 	
3944 	   return SCIP_OKAY;
3945 	}
3946 	
3947 	/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3948 	static
3949 	SCIP_RETCODE reformulateFactorizedBinaryQuadratic(
3950 	   SCIP*                 scip,               /**< SCIP data structure */
3951 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3952 	   SCIP_CONS*            cons,               /**< constraint */
3953 	   SCIP_VAR*             facvar,             /**< variable that has been factorized */
3954 	   SCIP_VAR**            vars,               /**< variables of sum_j c_ij x_j */
3955 	   SCIP_Real*            coefs,              /**< coefficients of sum_j c_ij x_j */
3956 	   int                   nvars,              /**< total number of variables in sum_j c_ij x_j */
3957 	   SCIP_EXPR**           newexpr,            /**< pointer to store the new expression */
3958 	   int*                  naddconss           /**< pointer to update the total number of added constraints (might be NULL) */
3959 	   )
3960 	{
3961 	   SCIP_VAR* auxvar;
3962 	   SCIP_CONS* newcons;
3963 	   SCIP_Real minact = 0.0;
3964 	   SCIP_Real maxact = 0.0;
3965 	   SCIP_Bool integral = TRUE;
3966 	   char name [SCIP_MAXSTRLEN];
3967 	   int i;
3968 	
3969 	   assert(facvar != NULL);
3970 	   assert(vars != NULL);
3971 	   assert(nvars > 1);
3972 	   assert(newexpr != NULL);
3973 	
3974 	   /* compute minimum and maximum activity of sum_j c_ij x_j */
3975 	   /* 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 */
3976 	   for( i = 0; i < nvars; ++i )
3977 	   {
3978 	      minact += MIN(coefs[i], 0.0);
3979 	      maxact += MAX(coefs[i], 0.0);
3980 	      integral = integral && SCIPisIntegral(scip, coefs[i]);
3981 	   }
3982 	   assert(minact <= maxact);
3983 	
3984 	   /* create and add auxiliary variable */
3985 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3986 	   SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
3987 	   SCIP_CALL( SCIPaddVar(scip, auxvar) );
3988 	
3989 	   /* create and add z - maxact x <= 0 */
3990 	   if( !SCIPisZero(scip, maxact) )
3991 	   {
3992 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3993 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3994 	      SCIP_CALL( SCIPaddCons(scip, newcons) );
3995 	      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3996 	      if( naddconss != NULL )
3997 	         ++(*naddconss);
3998 	   }
3999 	
4000 	   /* create and add  0 <= z - minact x */
4001 	   if( !SCIPisZero(scip, minact) )
4002 	   {
4003 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4004 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
4005 	      SCIP_CALL( SCIPaddCons(scip, newcons) );
4006 	      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4007 	      if( naddconss != NULL )
4008 	         ++(*naddconss);
4009 	   }
4010 	
4011 	   /* create and add minact <= sum_j c_j x_j - z + minact x_i */
4012 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4013 	   SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
4014 	   SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4015 	   if( !SCIPisZero(scip, minact) )
4016 	   {
4017 	      SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
4018 	   }
4019 	   SCIP_CALL( SCIPaddCons(scip, newcons) );
4020 	   SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4021 	   if( naddconss != NULL )
4022 	      ++(*naddconss);
4023 	
4024 	   /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4025 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4026 	   SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4027 	   SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4028 	   if( !SCIPisZero(scip, maxact) )
4029 	   {
4030 	      SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4031 	   }
4032 	   SCIP_CALL( SCIPaddCons(scip, newcons) );
4033 	   SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4034 	   if( naddconss != NULL )
4035 	      ++(*naddconss);
4036 	
4037 	   /* create variable expression */
4038 	   SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4039 	
4040 	   /* release auxvar */
4041 	   SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4042 	
4043 	   return SCIP_OKAY;
4044 	}
4045 	
4046 	/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4047 	static
4048 	SCIP_RETCODE getFactorizedBinaryQuadraticExpr(
4049 	   SCIP*                 scip,               /**< SCIP data structure */
4050 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4051 	   SCIP_CONS*            cons,               /**< constraint */
4052 	   SCIP_EXPR*            sumexpr,            /**< expression */
4053 	   int                   minterms,           /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4054 	   SCIP_EXPR**           newexpr,            /**< pointer to store the expression that represents the binary quadratic */
4055 	   int*                  naddconss           /**< pointer to update the total number of added constraints (might be NULL) */
4056 	   )
4057 	{
4058 	   SCIP_EXPR** exprs = NULL;
4059 	   SCIP_VAR** tmpvars = NULL;
4060 	   SCIP_VAR** vars = NULL;
4061 	   SCIP_VAR** xs = NULL;
4062 	   SCIP_VAR** ys = NULL;
4063 	   SCIP_Real* exprcoefs = NULL;
4064 	   SCIP_Real* tmpcoefs = NULL;
4065 	   SCIP_Real* sumcoefs;
4066 	   SCIP_Bool* isused  = NULL;
4067 	   int* childidxs = NULL;
4068 	   int* count = NULL;
4069 	   int nchildren;
4070 	   int nexprs = 0;
4071 	   int nterms;
4072 	   int nvars;
4073 	   int ntotalvars;
4074 	   int i;
4075 	
4076 	   assert(sumexpr != NULL);
4077 	   assert(minterms > 1);
4078 	   assert(newexpr != NULL);
4079 	
4080 	   *newexpr = NULL;
4081 	
4082 	   /* check whether sumexpr is indeed a sum */
4083 	   if( !SCIPisExprSum(scip, sumexpr) )
4084 	      return SCIP_OKAY;
4085 	
4086 	   nchildren = SCIPexprGetNChildren(sumexpr);
4087 	   sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4088 	   nvars = SCIPgetNVars(scip);
4089 	   ntotalvars = SCIPgetNTotalVars(scip);
4090 	
4091 	   /* check whether there are enough terms available */
4092 	   if( nchildren < minterms )
4093 	      return SCIP_OKAY;
4094 	
4095 	   /* allocate memory */
4096 	   SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4097 	   SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4098 	   SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4099 	
4100 	   /* collect all bilinear binary product terms */
4101 	   SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4102 	
4103 	   /* check whether there are enough terms available */
4104 	   if( nterms < minterms )
4105 	      goto TERMINATE;
4106 	
4107 	   /* store how often each variable appears in a bilinear binary product */
4108 	   SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
4109 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4110 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4111 	
4112 	   SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4113 	   SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4114 	   SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4115 	   SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4116 	
4117 	   for( i = 0; i < nterms; ++i )
4118 	   {
4119 	      int xidx;
4120 	      int yidx;
4121 	
4122 	      assert(xs[i] != NULL);
4123 	      assert(ys[i] != NULL);
4124 	
4125 	      xidx = SCIPvarGetIndex(xs[i]);
4126 	      assert(xidx < ntotalvars);
4127 	      yidx = SCIPvarGetIndex(ys[i]);
4128 	      assert(yidx < ntotalvars);
4129 	
4130 	      ++count[xidx];
4131 	      ++count[yidx];
4132 	
4133 	      SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4134 	      SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4135 	   }
4136 	
4137 	   /* sort variables; don't change order of count array because it depends on problem indices */
4138 	   {
4139 	      int* tmpcount;
4140 	
4141 	      SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4142 	      SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4143 	      SCIPfreeBufferArray(scip, &tmpcount);
4144 	   }
4145 	
4146 	   for( i = 0; i < nvars; ++i )
4147 	   {
4148 	      SCIP_VAR* facvar = vars[i];
4149 	      int ntmpvars = 0;
4150 	      int j;
4151 	
4152 	      /* skip candidate if there are not enough terms left */
4153 	      if( count[SCIPvarGetIndex(vars[i])] < minterms )
4154 	         continue;
4155 	
4156 	      SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4157 	
4158 	      /* collect variables for x_i * sum_j c_ij x_j */
4159 	      for( j = 0; j < nterms; ++j )
4160 	      {
4161 	         int childidx = childidxs[j];
4162 	         assert(childidx >= 0 && childidx < nchildren);
4163 	
4164 	         if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4165 	         {
4166 	            SCIP_Real coef;
4167 	            int xidx;
4168 	            int yidx;
4169 	
4170 	            coef = sumcoefs[childidx];
4171 	            assert(coef != 0.0);
4172 	
4173 	            /* collect corresponding variable */
4174 	            tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4175 	            tmpcoefs[ntmpvars] = coef;
4176 	            ++ntmpvars;
4177 	
4178 	            /* update counters */
4179 	            xidx = SCIPvarGetIndex(xs[j]);
4180 	            assert(xidx < ntotalvars);
4181 	            yidx = SCIPvarGetIndex(ys[j]);
4182 	            assert(yidx < ntotalvars);
4183 	            --count[xidx];
4184 	            --count[yidx];
4185 	            assert(count[xidx] >= 0);
4186 	            assert(count[yidx] >= 0);
4187 	
4188 	            /* mark term to be used */
4189 	            isused[childidx] = TRUE;
4190 	         }
4191 	      }
4192 	      assert(ntmpvars >= minterms);
4193 	      assert(SCIPvarGetIndex(facvar) < ntotalvars);
4194 	      assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4195 	
4196 	      /* create required constraints and store the generated expression */
4197 	      SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4198 	      exprcoefs[nexprs] = 1.0;
4199 	      ++nexprs;
4200 	   }
4201 	
4202 	   /* factorization was only successful if at least one expression has been generated */
4203 	   if( nexprs > 0 )
4204 	   {
4205 	      int nexprsold = nexprs;
4206 	
4207 	      /* add all children of the sum that have not been used */
4208 	      for( i = 0; i < nchildren; ++i )
4209 	      {
4210 	         if( !isused[i] )
4211 	         {
4212 	            exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4213 	            exprcoefs[nexprs] = sumcoefs[i];
4214 	            ++nexprs;
4215 	         }
4216 	      }
4217 	
4218 	      /* create a new sum expression */
4219 	      SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4220 	
4221 	      /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4222 	      for( i = 0; i < nexprsold; ++i )
4223 	      {
4224 	         SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4225 	      }
4226 	   }
4227 	
4228 	TERMINATE:
4229 	   /* free memory */
4230 	   SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4231 	   SCIPfreeBufferArrayNull(scip, &tmpvars);
4232 	   SCIPfreeBufferArrayNull(scip, &exprcoefs);
4233 	   SCIPfreeBufferArrayNull(scip, &exprs);
4234 	   SCIPfreeBufferArrayNull(scip, &vars);
4235 	   SCIPfreeBufferArrayNull(scip, &isused);
4236 	   SCIPfreeBufferArrayNull(scip, &count);
4237 	   SCIPfreeBufferArray(scip, &childidxs);
4238 	   SCIPfreeBufferArray(scip, &ys);
4239 	   SCIPfreeBufferArray(scip, &xs);
4240 	
4241 	   return SCIP_OKAY;
4242 	}
4243 	
4244 	/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4245 	static
4246 	SCIP_RETCODE getBinaryProductExprDo(
4247 	   SCIP*                 scip,               /**< SCIP data structure */
4248 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4249 	   SCIP_EXPR*            prodexpr,           /**< product expression */
4250 	   SCIP_EXPR**           newexpr,            /**< pointer to store the expression that represents the product */
4251 	   int*                  naddconss,          /**< pointer to update the total number of added constraints (might be NULL) */
4252 	   SCIP_Bool             empathy4and         /**< whether to use an AND constraint, if possible */
4253 	   )
4254 	{
4255 	   SCIP_VAR** vars;
4256 	   SCIP_CONS* cons;
4257 	   SCIP_Real* coefs;
4258 	   SCIP_VAR* w;
4259 	   char name[SCIP_MAXSTRLEN];
4260 	   int nchildren;
4261 	   int i;
4262 	
4263 	   assert(conshdlr != NULL);
4264 	   assert(prodexpr != NULL);
4265 	   assert(SCIPisExprProduct(scip, prodexpr));
4266 	   assert(newexpr != NULL);
4267 	
4268 	   nchildren = SCIPexprGetNChildren(prodexpr);
4269 	   assert(nchildren >= 2);
4270 	
4271 	   /* memory to store the variables of the variable expressions (+1 for w) */
4272 	   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4273 	   SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4274 	
4275 	   /* prepare the names of the variable and the constraints */
4276 	   (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform");
4277 	   for( i = 0; i < nchildren; ++i )
4278 	   {
4279 	      vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4280 	      coefs[i] = 1.0;
4281 	      assert(vars[i] != NULL);
4282 	      (void) strcat(name, "_");
4283 	      (void) strcat(name, SCIPvarGetName(vars[i]));
4284 	   }
4285 	
4286 	   /* create and add variable */
4287 	   SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4288 	   SCIP_CALL( SCIPaddVar(scip, w) );
4289 	   SCIPdebugMsg(scip, "  created auxiliary variable %s\n", name);
4290 	
4291 	   /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4292 	   if( nchildren == 2 && !empathy4and )
4293 	   {
4294 	      SCIP_VAR* x = vars[0];
4295 	      SCIP_VAR* y = vars[1];
4296 	
4297 	      assert(x != NULL);
4298 	      assert(y != NULL);
4299 	      assert(x != y);
4300 	
4301 	      /* create and add x - w >= 0 */
4302 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4303 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4304 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4305 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4306 	
4307 	      /* create and add y - w >= 0 */
4308 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4309 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4310 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4311 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4312 	
4313 	      /* create and add x + y - w <= 1 */
4314 	      vars[2] = w;
4315 	      coefs[2] = -1.0;
4316 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4317 	      SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4318 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4319 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4320 	
4321 	      /* update number of added constraints */
4322 	      if( naddconss != NULL )
4323 	         *naddconss += 3;
4324 	   }
4325 	   else
4326 	   {
4327 	      /* create, add, and release AND constraint */
4328 	      SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4329 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4330 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4331 	      SCIPdebugMsg(scip, "  create AND constraint\n");
4332 	
4333 	      /* update number of added constraints */
4334 	      if( naddconss != NULL )
4335 	         *naddconss += 1;
4336 	   }
4337 	
4338 	   /* create variable expression */
4339 	   SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4340 	
4341 	   /* release created variable */
4342 	   SCIP_CALL( SCIPreleaseVar(scip, &w) );
4343 	
4344 	   /* free memory */
4345 	   SCIPfreeBufferArray(scip, &coefs);
4346 	   SCIPfreeBufferArray(scip, &vars);
4347 	
4348 	   return SCIP_OKAY;
4349 	}
4350 	
4351 	/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4352 	static
4353 	SCIP_RETCODE getBinaryProductExpr(
4354 	   SCIP*                 scip,               /**< SCIP data structure */
4355 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4356 	   SCIP_HASHMAP*         exprmap,            /**< map to remember generated variables for visited product expressions */
4357 	   SCIP_EXPR*            prodexpr,           /**< product expression */
4358 	   SCIP_EXPR**           newexpr,            /**< pointer to store the expression that represents the product */
4359 	   int*                  naddconss,          /**< pointer to update the total number of added constraints (might be NULL) */
4360 	   int*                  nchgcoefs           /**< pointer to update the total number of changed coefficients (might be NULL) */
4361 	   )
4362 	{
4363 	   SCIP_CONSHDLRDATA* conshdlrdata;
4364 	   int nchildren;
4365 	
4366 	   assert(prodexpr != NULL);
4367 	   assert(newexpr != NULL);
4368 	
4369 	   *newexpr = NULL;
4370 	
4371 	   /* only consider products of binary variables */
4372 	   if( !isBinaryProduct(scip, prodexpr) )
4373 	      return SCIP_OKAY;
4374 	
4375 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4376 	   assert(conshdlrdata != NULL);
4377 	   nchildren = SCIPexprGetNChildren(prodexpr);
4378 	   assert(nchildren >= 2);
4379 	
4380 	   /* check whether there is already an expression that represents the product */
4381 	   if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4382 	   {
4383 	      *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4384 	      assert(*newexpr != NULL);
4385 	
4386 	      /* capture expression */
4387 	      SCIPcaptureExpr(*newexpr);
4388 	   }
4389 	   else
4390 	   {
4391 	      SCIPdebugMsg(scip, "  product expression %p has been considered for the first time\n", (void*)prodexpr);
4392 	
4393 	      if( nchildren == 2 )
4394 	      {
4395 	         SCIP_CLIQUE** xcliques;
4396 	         SCIP_VAR* x;
4397 	         SCIP_VAR* y;
4398 	         SCIP_Bool found_clique = FALSE;
4399 	         int c;
4400 	
4401 	         /* get variables from the product expression */
4402 	         x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4403 	         assert(x != NULL);
4404 	         y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4405 	         assert(y != NULL);
4406 	         assert(x != y);
4407 	
4408 	         /* first try to find a clique containing both variables */
4409 	         xcliques = SCIPvarGetCliques(x, TRUE);
4410 	
4411 	         /* look in cliques containing x */
4412 	         for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4413 	         {
4414 	            if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4415 	            {
4416 	               /* create zero value expression */
4417 	               SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4418 	
4419 	               if( nchgcoefs != NULL )
4420 	                  *nchgcoefs += 1;
4421 	
4422 	               found_clique = TRUE;
4423 	               break;
4424 	            }
4425 	
4426 	            if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4427 	            {
4428 	               /* create variable expression for x */
4429 	               SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4430 	
4431 	               if( nchgcoefs != NULL )
4432 	                  *nchgcoefs += 2;
4433 	
4434 	               found_clique = TRUE;
4435 	               break;
4436 	            }
4437 	         }
4438 	
4439 	         if( !found_clique )
4440 	         {
4441 	            xcliques = SCIPvarGetCliques(x, FALSE);
4442 	
4443 	            /* look in cliques containing complement of x */
4444 	            for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4445 	            {
4446 	               if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4447 	               {
4448 	                  /* create variable expression for y */
4449 	                  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4450 	
4451 	                  if( nchgcoefs != NULL )
4452 	                     *nchgcoefs += 1;
4453 	
4454 	                  found_clique = TRUE;
4455 	                  break;
4456 	               }
4457 	
4458 	               if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4459 	               {
4460 	                  /* create sum expression */
4461 	                  SCIP_EXPR* sum_children[2];
4462 	                  SCIP_Real sum_coefs[2];
4463 	                  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4464 	                  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4465 	                  sum_coefs[0] = 1.0;
4466 	                  sum_coefs[1] = 1.0;
4467 	                  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4468 	
4469 	                  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4470 	                  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4471 	
4472 	                  if( nchgcoefs != NULL )
4473 	                     *nchgcoefs += 3;
4474 	
4475 	                  found_clique = TRUE;
4476 	                  break;
4477 	               }
4478 	            }
4479 	         }
4480 	
4481 	         /* if the variables are not in a clique, do standard linearization */
4482 	         if( !found_clique )
4483 	         {
4484 	            SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4485 	         }
4486 	      }
4487 	      else
4488 	      {
4489 	         /* linearize binary product using an AND constraint because nchildren > 2 */
4490 	         SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4491 	      }
4492 	
4493 	      /* hash variable expression */
4494 	      SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4495 	   }
4496 	
4497 	   return SCIP_OKAY;
4498 	}
4499 	
4500 	/** helper function to replace binary products in a given constraint */
4501 	static
4502 	SCIP_RETCODE replaceBinaryProducts(
4503 	   SCIP*                 scip,               /**< SCIP data structure */
4504 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4505 	   SCIP_CONS*            cons,               /**< constraint */
4506 	   SCIP_HASHMAP*         exprmap,            /**< map to remember generated variables for visited product expressions */
4507 	   SCIP_EXPRITER*        it,                 /**< expression iterator */
4508 	   int*                  naddconss,          /**< pointer to update the total number of added constraints (might be NULL) */
4509 	   int*                  nchgcoefs           /**< pointer to update the total number of changed coefficients (might be NULL) */
4510 	   )
4511 	{
4512 	   SCIP_CONSHDLRDATA* conshdlrdata;
4513 	   SCIP_CONSDATA* consdata;
4514 	   SCIP_EXPR* expr;
4515 	
4516 	   assert(conshdlr != NULL);
4517 	   assert(cons != NULL);
4518 	   assert(exprmap != NULL);
4519 	   assert(it != NULL);
4520 	
4521 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4522 	   assert(conshdlrdata != NULL);
4523 	
4524 	   consdata = SCIPconsGetData(cons);
4525 	   assert(consdata != NULL);
4526 	   assert(consdata->expr != NULL);
4527 	
4528 	   SCIPdebugMsg(scip, "  check constraint %s\n", SCIPconsGetName(cons));
4529 	
4530 	   for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4531 	   {
4532 	      SCIP_EXPR* newexpr = NULL;
4533 	      SCIP_EXPR* childexpr;
4534 	      int childexpridx;
4535 	
4536 	      childexpridx = SCIPexpriterGetChildIdxDFS(it);
4537 	      assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4538 	      childexpr = SCIPexpriterGetChildExprDFS(it);
4539 	      assert(childexpr != NULL);
4540 	
4541 	      /* try to factorize variables in a sum expression that contains several products of binary variables */
4542 	      if( conshdlrdata->reformbinprodsfac > 1 )
4543 	      {
4544 	         SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4545 	      }
4546 	
4547 	      /* try to create an expression that represents a product of binary variables */
4548 	      if( newexpr == NULL )
4549 	      {
4550 	         SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4551 	      }
4552 	
4553 	      if( newexpr != NULL )
4554 	      {
4555 	         assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4556 	
4557 	         /* replace product expression */
4558 	         SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4559 	
4560 	         /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4561 	         SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4562 	
4563 	         /* mark the constraint to not be simplified anymore */
4564 	         consdata->issimplified = FALSE;
4565 	      }
4566 	   }
4567 	
4568 	   return SCIP_OKAY;
4569 	}
4570 	
4571 	/** reformulates products of binary variables during presolving in the following way:
4572 	 *
4573 	 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4574 	 * 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}:
4575 	 * \f[
4576 	 *    z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4577 	 * \f]
4578 	 *
4579 	 * 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$.
4580 	 * These cliques allow for a better reformulation. There are four cases:
4581 	 *
4582 	 *    1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4583 	 *    2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4584 	 *    3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4585 	 *    4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4586 	 *
4587 	 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4588 	 *
4589 	 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4590 	 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4591 	 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4592 	 * Such a lower sum is reformulated with only one extra variable w_i:
4593 	 * \f{align}{
4594 	 *    \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4595 	 *    \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4596 	 *    \text{minact}\, x_i & \leq w_i, \\
4597 	 *    w_i &\leq \text{maxact}\, x_i, \\
4598 	 *    \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4599 	 *    \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4600 	 * \f}
4601 	 * 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
4602 	 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4603 	 * of terms are prioritized.
4604 	 */
4605 	static
4606 	SCIP_RETCODE presolveBinaryProducts(
4607 	   SCIP*                 scip,               /**< SCIP data structure */
4608 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4609 	   SCIP_CONS**           conss,              /**< constraints */
4610 	   int                   nconss,             /**< total number of constraints */
4611 	   int*                  naddconss,          /**< pointer to store the total number of added constraints (might be NULL) */
4612 	   int*                  nchgcoefs           /**< pointer to store the total number of changed coefficients (might be NULL) */
4613 	   )
4614 	{
4615 	   SCIP_CONSHDLRDATA* conshdlrdata;
4616 	   SCIP_HASHMAP* exprmap;
4617 	   SCIP_EXPRITER* it;
4618 	   int c;
4619 	
4620 	   assert(conshdlr != NULL);
4621 	
4622 	   /* no nonlinear constraints or binary variables -> skip */
4623 	   if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4624 	      return SCIP_OKAY;
4625 	   assert(conss != NULL);
4626 	
4627 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4628 	   assert(conshdlrdata != NULL);
4629 	
4630 	   /* create expression hash map */
4631 	   SCIP_CALL( SCIPhashmapCreate(&exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
4632 	
4633 	   /* create expression iterator */
4634 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4635 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4636 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
4637 	
4638 	   SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4639 	
4640 	   for( c = 0; c < nconss; ++c )
4641 	   {
4642 	      SCIP_CONSDATA* consdata;
4643 	      SCIP_EXPR* newexpr = NULL;
4644 	
4645 	      assert(conss[c] != NULL);
4646 	
4647 	      consdata = SCIPconsGetData(conss[c]);
4648 	      assert(consdata != NULL);
4649 	
4650 	      /* try to reformulate the root expression */
4651 	      if( conshdlrdata->reformbinprodsfac > 1 )
4652 	      {
4653 	         SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4654 	      }
4655 	
4656 	      /* release the root node if another expression has been found */
4657 	      if( newexpr != NULL )
4658 	      {
4659 	         SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4660 	         consdata->expr = newexpr;
4661 	
4662 	         /* mark constraint to be not simplified anymore */
4663 	         consdata->issimplified = FALSE;
4664 	      }
4665 	
4666 	      /* replace each product of binary variables separately */
4667 	      SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4668 	   }
4669 	
4670 	   /* free memory */
4671 	   SCIPhashmapFree(&exprmap);
4672 	   SCIPfreeExpriter(&it);
4673 	
4674 	   return SCIP_OKAY;
4675 	}
4676 	
4677 	/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4678 	 *
4679 	 *  Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4680 	 *  Then scale by -1 if
4681 	 *  - \f$n_+ < n_-\f$, or
4682 	 *  - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4683 	 */
4684 	static
4685 	SCIP_RETCODE scaleConsSides(
4686 	   SCIP*                 scip,               /**< SCIP data structure */
4687 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
4688 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
4689 	   SCIP_Bool*            changed             /**< buffer to store if the expression of cons changed */
4690 	   )
4691 	{
4692 	   SCIP_CONSDATA* consdata;
4693 	   int i;
4694 	
4695 	   assert(cons != NULL);
4696 	
4697 	   consdata = SCIPconsGetData(cons);
4698 	   assert(consdata != NULL);
4699 	
4700 	   if( SCIPisExprSum(scip, consdata->expr) )
4701 	   {
4702 	      SCIP_Real* coefs;
4703 	      SCIP_Real constant;
4704 	      int nchildren;
4705 	      int counter = 0;
4706 	
4707 	      coefs = SCIPgetCoefsExprSum(consdata->expr);
4708 	      constant = SCIPgetConstantExprSum(consdata->expr);
4709 	      nchildren = SCIPexprGetNChildren(consdata->expr);
4710 	
4711 	      /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4712 	      if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4713 	      {
4714 	         SCIP_EXPR* expr;
4715 	         expr = consdata->expr;
4716 	
4717 	         consdata->expr = SCIPexprGetChildren(expr)[0];
4718 	         assert(!SCIPisExprSum(scip, consdata->expr));
4719 	
4720 	         SCIPcaptureExpr(consdata->expr);
4721 	
4722 	         SCIPswapReals(&consdata->lhs, &consdata->rhs);
4723 	         consdata->lhs = -consdata->lhs;
4724 	         consdata->rhs = -consdata->rhs;
4725 	
4726 	         SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4727 	         *changed = TRUE;
4728 	         return SCIP_OKAY;
4729 	      }
4730 	
4731 	      /* compute n_+ - n_i */
4732 	      for( i = 0; i < nchildren; ++i )
4733 	         counter += coefs[i] > 0 ? 1 : -1;
4734 	
4735 	      if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4736 	      {
4737 	         SCIP_EXPR* expr;
4738 	         SCIP_Real* newcoefs;
4739 	
4740 	         /* allocate memory */
4741 	         SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4742 	
4743 	         for( i = 0; i < nchildren; ++i )
4744 	            newcoefs[i] = -coefs[i];
4745 	
4746 	         /* create a new sum expression */
4747 	         SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4748 	
4749 	         /* replace expression in constraint data and scale sides */
4750 	         SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4751 	         consdata->expr = expr;
4752 	         SCIPswapReals(&consdata->lhs, &consdata->rhs);
4753 	         consdata->lhs = -consdata->lhs;
4754 	         consdata->rhs = -consdata->rhs;
4755 	
4756 	         /* free memory */
4757 	         SCIPfreeBufferArray(scip, &newcoefs);
4758 	
4759 	         *changed = TRUE;
4760 	      }
4761 	   }
4762 	
4763 	   return SCIP_OKAY;
4764 	}
4765 	
4766 	/** forbid multiaggrations of variables that appear nonlinear in constraints */
4767 	static
4768 	SCIP_RETCODE forbidNonlinearVariablesMultiaggration(
4769 	   SCIP*                 scip,               /**< SCIP data structure */
4770 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4771 	   SCIP_CONS**           conss,              /**< constraints */
4772 	   int                   nconss              /**< number of constraints */
4773 	   )
4774 	{
4775 	   SCIP_EXPRITER* it;
4776 	   SCIP_CONSDATA* consdata;
4777 	   SCIP_EXPR* expr;
4778 	   int c;
4779 	
4780 	   assert(scip != NULL);
4781 	   assert(conshdlr != NULL);
4782 	
4783 	   if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4784 	      return SCIP_OKAY;
4785 	
4786 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4787 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4788 	
4789 	   for( c = 0; c < nconss; ++c )
4790 	   {
4791 	      consdata = SCIPconsGetData(conss[c]);
4792 	      assert(consdata != NULL);
4793 	
4794 	      /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4795 	       *   i.e., skip children of sum that are variables
4796 	       */
4797 	      if( SCIPisExprSum(scip, consdata->expr) )
4798 	      {
4799 	         int i;
4800 	         SCIP_EXPR* child;
4801 	         for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4802 	         {
4803 	            child = SCIPexprGetChildren(consdata->expr)[i];
4804 	
4805 	            /* skip variable expression, as they correspond to a linear term */
4806 	            if( SCIPisExprVar(scip, child) )
4807 	               continue;
4808 	
4809 	            for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4810 	               if( SCIPisExprVar(scip, expr) )
4811 	               {
4812 	                  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPgetVarExprVar(expr)) );
4813 	               }
4814 	         }
4815 	      }
4816 	      else
4817 	      {
4818 	         for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4819 	            if( SCIPisExprVar(scip, expr) )
4820 	            {
4821 	               SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPgetVarExprVar(expr)) );
4822 	            }
4823 	      }
4824 	   }
4825 	
4826 	   SCIPfreeExpriter(&it);
4827 	
4828 	   return SCIP_OKAY;
4829 	}
4830 	
4831 	/** simplifies expressions and replaces common subexpressions for a set of constraints
4832 	 * @todo put the constant to the constraint sides
4833 	 */
4834 	static
4835 	SCIP_RETCODE canonicalizeConstraints(
4836 	   SCIP*                 scip,               /**< SCIP data structure */
4837 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4838 	   SCIP_CONS**           conss,              /**< constraints */
4839 	   int                   nconss,             /**< total number of constraints */
4840 	   SCIP_PRESOLTIMING     presoltiming,       /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4841 	   SCIP_Bool*            infeasible,         /**< buffer to store whether infeasibility has been detected */
4842 	   int*                  ndelconss,          /**< counter to add number of deleted constraints, or NULL */
4843 	   int*                  naddconss,          /**< counter to add number of added constraints, or NULL */
4844 	   int*                  nchgcoefs           /**< counter to add number of changed coefficients, or NULL */
4845 	   )
4846 	{
4847 	   SCIP_CONSHDLRDATA* conshdlrdata;
4848 	   SCIP_CONSDATA* consdata;
4849 	   int* nlockspos;
4850 	   int* nlocksneg;
4851 	   SCIP_Bool havechange;
4852 	   int i;
4853 	
4854 	   assert(scip != NULL);
4855 	   assert(conshdlr != NULL);
4856 	   assert(conss != NULL);
4857 	   assert(nconss > 0);
4858 	   assert(infeasible != NULL);
4859 	
4860 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4861 	   assert(conshdlrdata != NULL);
4862 	
4863 	   /* update number of canonicalize calls */
4864 	   ++(conshdlrdata->ncanonicalizecalls);
4865 	
4866 	   SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4867 	
4868 	   *infeasible = FALSE;
4869 	
4870 	   /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4871 	   havechange = conshdlrdata->ncanonicalizecalls == 1;
4872 	
4873 	   /* free nonlinear handlers information from expressions */  /* TODO can skip this in first presolve round */
4874 	   SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4875 	
4876 	   /* allocate memory for storing locks of each constraint */
4877 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4878 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4879 	
4880 	   /* unlock all constraints */
4881 	   for( i = 0; i < nconss; ++i )
4882 	   {
4883 	      assert(conss[i] != NULL);
4884 	
4885 	      consdata = SCIPconsGetData(conss[i]);
4886 	      assert(consdata != NULL);
4887 	
4888 	      /* remember locks */
4889 	      nlockspos[i] = consdata->nlockspos;
4890 	      nlocksneg[i] = consdata->nlocksneg;
4891 	
4892 	      /* remove locks */
4893 	      SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4894 	      assert(consdata->nlockspos == 0);
4895 	      assert(consdata->nlocksneg == 0);
4896 	   }
4897 	
4898 	#ifndef NDEBUG
4899 	   /* check whether all locks of each expression have been removed */
4900 	   for( i = 0; i < nconss; ++i )
4901 	   {
4902 	      SCIP_EXPR* expr;
4903 	      SCIP_EXPRITER* it;
4904 	
4905 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4906 	
4907 	      consdata = SCIPconsGetData(conss[i]);
4908 	      assert(consdata != NULL);
4909 	
4910 	      SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_RTOPOLOGIC, TRUE) );
4911 	      for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4912 	      {
4913 	         assert(expr != NULL);
4914 	         assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4915 	         assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4916 	      }
4917 	      SCIPfreeExpriter(&it);
4918 	   }
4919 	#endif
4920 	
4921 	   /* reformulate products of binary variables */
4922 	   if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4923 	      && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4924 	   {
4925 	      int tmpnaddconss = 0;
4926 	      int tmpnchgcoefs = 0;
4927 	
4928 	      /* call this function before simplification because expressions might not be simplified after reformulating
4929 	       * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4930 	       */
4931 	      SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4932 	
4933 	      /* update counters */
4934 	      if( naddconss != NULL )
4935 	         *naddconss = tmpnaddconss;
4936 	      if( nchgcoefs != NULL )
4937 	         *nchgcoefs = tmpnchgcoefs;
4938 	
4939 	      /* check whether at least one expression has changed */
4940 	      if( tmpnaddconss + tmpnchgcoefs > 0 )
4941 	         havechange = TRUE;
4942 	   }
4943 	
4944 	   for( i = 0; i < nconss; ++i )
4945 	   {
4946 	      consdata = SCIPconsGetData(conss[i]);
4947 	      assert(consdata != NULL);
4948 	
4949 	      /* call simplify for each expression */
4950 	      if( !consdata->issimplified && consdata->expr != NULL )
4951 	      {
4952 	         SCIP_EXPR* simplified;
4953 	         SCIP_Bool changed;
4954 	
4955 	         changed = FALSE;
4956 	         SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4957 	         consdata->issimplified = TRUE;
4958 	
4959 	         if( changed )
4960 	            havechange = TRUE;
4961 	
4962 	         /* 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").
4963 	          * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4964 	          */
4965 	         if( simplified != consdata->expr )
4966 	         {
4967 	            assert(changed);
4968 	
4969 	            /* release old expression */
4970 	            SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4971 	
4972 	            /* store simplified expression */
4973 	            consdata->expr = simplified;
4974 	         }
4975 	         else
4976 	         {
4977 	            /* The simplify captures simplified in any case, also if nothing has changed.
4978 	             * Therefore, we have to release it here.
4979 	             */
4980 	            SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
4981 	         }
4982 	
4983 	         if( *infeasible )
4984 	            break;
4985 	
4986 	         /* scale constraint sides */
4987 	         SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
4988 	
4989 	         if( changed )
4990 	            havechange = TRUE;
4991 	
4992 	         /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4993 	         if( SCIPisExprValue(scip, consdata->expr) )
4994 	         {
4995 	            SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
4996 	            if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
4997 	                (!SCIPisInfinity(scip,  consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
4998 	            {
4999 	               SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5000 	               SCIPdebugPrintCons(scip, conss[i], NULL);
5001 	               *infeasible = TRUE;
5002 	               break;
5003 	            }
5004 	            else
5005 	            {
5006 	               SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5007 	               SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5008 	               if( ndelconss != NULL )
5009 	                  ++*ndelconss;
5010 	               havechange = TRUE;
5011 	            }
5012 	         }
5013 	      }
5014 	   }
5015 	
5016 	   /* replace common subexpressions */
5017 	   if( havechange && !*infeasible )
5018 	   {
5019 	      SCIP_CONS** consssorted;
5020 	      SCIP_EXPR** rootexprs;
5021 	      SCIP_Bool replacedroot;
5022 	
5023 	      SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5024 	      for( i = 0; i < nconss; ++i )
5025 	         rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5026 	
5027 	      SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5028 	
5029 	      /* update pointer to root expr in constraints, if any has changed
5030 	       * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5031 	       */
5032 	      if( replacedroot )
5033 	         for( i = 0; i < nconss; ++i )
5034 	            SCIPconsGetData(conss[i])->expr = rootexprs[i];
5035 	
5036 	      SCIPfreeBufferArray(scip, &rootexprs);
5037 	
5038 	      /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5039 	       * been changed after simplification; now we completely recollect all variable expression and variable events
5040 	       */
5041 	
5042 	      /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5043 	       * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5044 	       */
5045 	      SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5046 	      SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5047 	
5048 	      for( i = nconss-1; i >= 0; --i )
5049 	      {
5050 	         assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5051 	         if( SCIPconsIsDeleted(consssorted[i]) )
5052 	            continue;
5053 	
5054 	         SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5055 	         SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5056 	      }
5057 	      for( i = 0; i < nconss; ++i )
5058 	      {
5059 	         if( SCIPconsIsDeleted(consssorted[i]) )
5060 	            continue;
5061 	
5062 	         SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5063 	         SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5064 	      }
5065 	
5066 	      SCIPfreeBufferArray(scip, &consssorted);
5067 	
5068 	      /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5069 	       * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5070 	       * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5071 	       */
5072 	      SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5073 	   }
5074 	
5075 	   /* restore locks */
5076 	   for( i = 0; i < nconss; ++i )
5077 	   {
5078 	      if( SCIPconsIsDeleted(conss[i]) )
5079 	         continue;
5080 	
5081 	      SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5082 	   }
5083 	
5084 	   /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5085 	    * TODO can we skip this in presoltiming fast?
5086 	    */
5087 	   if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5088 	   {
5089 	      /* reset one of the number of detections counter to count only current presolving round */
5090 	      for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5091 	         SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5092 	
5093 	      SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5094 	   }
5095 	
5096 	   /* free allocated memory */
5097 	   SCIPfreeBufferArray(scip, &nlocksneg);
5098 	   SCIPfreeBufferArray(scip, &nlockspos);
5099 	
5100 	   SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5101 	
5102 	   return SCIP_OKAY;
5103 	}
5104 	
5105 	/** merges constraints that have the same root expression */
5106 	static
5107 	SCIP_RETCODE presolveMergeConss(
5108 	   SCIP*                 scip,               /**< SCIP data structure */
5109 	   SCIP_CONS**           conss,              /**< constraints to process */
5110 	   int                   nconss,             /**< number of constraints */
5111 	   SCIP_Bool*            success             /**< pointer to store whether at least one constraint could be deleted */
5112 	   )
5113 	{
5114 	   SCIP_HASHMAP* expr2cons;
5115 	   SCIP_Bool* updatelocks;
5116 	   int* nlockspos;
5117 	   int* nlocksneg;
5118 	   int c;
5119 	
5120 	   assert(success != NULL);
5121 	
5122 	   *success = FALSE;
5123 	
5124 	   /* not enough constraints available */
5125 	   if( nconss <= 1 )
5126 	      return SCIP_OKAY;
5127 	
5128 	   SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5129 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5130 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5131 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5132 	
5133 	   for( c = 0; c < nconss; ++c )
5134 	   {
5135 	      SCIP_CONSDATA* consdata;
5136 	
5137 	      /* ignore deleted constraints */
5138 	      if( SCIPconsIsDeleted(conss[c]) )
5139 	         continue;
5140 	
5141 	      consdata = SCIPconsGetData(conss[c]);
5142 	      assert(consdata != NULL);
5143 	
5144 	      /* add expression to the hash map if not seen so far */
5145 	      if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5146 	      {
5147 	         SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5148 	      }
5149 	      else
5150 	      {
5151 	         SCIP_CONSDATA* imgconsdata;
5152 	         int idx;
5153 	
5154 	         idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5155 	         assert(idx >= 0 && idx < nconss);
5156 	
5157 	         imgconsdata = SCIPconsGetData(conss[idx]);
5158 	         assert(imgconsdata != NULL);
5159 	         assert(imgconsdata->expr == consdata->expr);
5160 	
5161 	         SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5162 	            SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5163 	
5164 	         /* check whether locks need to be updated */
5165 	         if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5166 	            || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5167 	         {
5168 	            nlockspos[idx] = imgconsdata->nlockspos;
5169 	            nlocksneg[idx] = imgconsdata->nlocksneg;
5170 	            SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5171 	            updatelocks[idx] = TRUE;
5172 	         }
5173 	
5174 	         /* update constraint sides */
5175 	         imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5176 	         imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5177 	
5178 	         /* delete constraint */
5179 	         SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5180 	         *success = TRUE;
5181 	      }
5182 	   }
5183 	
5184 	   /* restore locks of updated constraints */
5185 	   if( *success )
5186 	   {
5187 	      for( c = 0; c < nconss; ++c )
5188 	      {
5189 	         if( updatelocks[c] )
5190 	         {
5191 	            SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5192 	         }
5193 	      }
5194 	   }
5195 	
5196 	   /* free memory */
5197 	   SCIPfreeBufferArray(scip, &nlocksneg);
5198 	   SCIPfreeBufferArray(scip, &nlockspos);
5199 	   SCIPfreeBufferArray(scip, &updatelocks);
5200 	   SCIPhashmapFree(&expr2cons);
5201 	
5202 	   return SCIP_OKAY;
5203 	}
5204 	
5205 	/** interval evaluation of variables as used in redundancy check
5206 	 *
5207 	 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5208 	 */
5209 	static
5210 	SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5211 	{  /*lint --e{715}*/
5212 	   SCIP_CONSHDLRDATA* conshdlrdata;
5213 	   SCIP_INTERVAL interval;
5214 	   SCIP_Real lb;
5215 	   SCIP_Real ub;
5216 	
5217 	   assert(scip != NULL);
5218 	   assert(var != NULL);
5219 	
5220 	   conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5221 	   assert(conshdlrdata != NULL);
5222 	
5223 	   if( conshdlrdata->globalbounds )
5224 	   {
5225 	      lb = SCIPvarGetLbGlobal(var);
5226 	      ub = SCIPvarGetUbGlobal(var);
5227 	   }
5228 	   else
5229 	   {
5230 	      lb = SCIPvarGetLbLocal(var);
5231 	      ub = SCIPvarGetUbLocal(var);
5232 	   }
5233 	   assert(lb <= ub);  /* can SCIP ensure by now that variable bounds are not contradicting? */
5234 	
5235 	   /* relax variable bounds, if there are bounds and variable is not fixed
5236 	    * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5237 	    */
5238 	   if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5239 	   {
5240 	      if( !SCIPisInfinity(scip, -lb) )
5241 	         lb -= SCIPfeastol(scip);
5242 	
5243 	      if( !SCIPisInfinity(scip, ub) )
5244 	         ub += SCIPfeastol(scip);
5245 	   }
5246 	
5247 	   /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5248 	   lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
5249 	   ub =  infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY,  ub);
5250 	   assert(lb <= ub);
5251 	
5252 	   SCIPintervalSetBounds(&interval, lb, ub);
5253 	
5254 	   return interval;
5255 	}
5256 	
5257 	/** removes constraints that are always feasible or very simple
5258 	 *
5259 	 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5260 	 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5261 	 * might violate variable bounds by up to feastol, too.
5262 	 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5263 	 *
5264 	 * Also removes constraints of the form lhs &le; variable &le; rhs.
5265 	 *
5266 	 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5267 	 *
5268 	 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5269 	 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5270 	 * would appear as if the constraint is redundant.
5271 	 */
5272 	static
5273 	SCIP_RETCODE presolveRedundantConss(
5274 	   SCIP*                 scip,               /**< SCIP data structure */
5275 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
5276 	   SCIP_CONS**           conss,              /**< constraints to propagate */
5277 	   int                   nconss,             /**< total number of constraints */
5278 	   SCIP_Bool*            cutoff,             /**< pointer to store whether infeasibility has been identified */
5279 	   int*                  ndelconss,          /**< buffer to add the number of deleted constraints */
5280 	   int*                  nchgbds             /**< buffer to add the number of variable bound tightenings */
5281 	   )
5282 	{
5283 	   SCIP_CONSHDLRDATA* conshdlrdata;
5284 	   SCIP_CONSDATA* consdata;
5285 	   SCIP_INTERVAL activity;
5286 	   SCIP_INTERVAL sides;
5287 	   int i;
5288 	
5289 	   assert(scip != NULL);
5290 	   assert(conshdlr != NULL);
5291 	   assert(conss != NULL);
5292 	   assert(nconss >= 0);
5293 	   assert(cutoff != NULL);
5294 	   assert(ndelconss != NULL);
5295 	   assert(nchgbds != NULL);
5296 	
5297 	   /* no constraints to check */
5298 	   if( nconss == 0 )
5299 	      return SCIP_OKAY;
5300 	
5301 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
5302 	   assert(conshdlrdata != NULL);
5303 	
5304 	   /* increase curboundstag and set lastvaractivitymethodchange
5305 	    * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5306 	    * for the redundancy check differently than for domain propagation
5307 	    * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5308 	    */
5309 	   ++conshdlrdata->curboundstag;
5310 	   assert(conshdlrdata->curboundstag > 0);
5311 	   conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5312 	   conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5313 	   conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5314 	
5315 	   SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5316 	
5317 	   *cutoff = FALSE;
5318 	   for( i = 0; i < nconss; ++i )
5319 	   {
5320 	      if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5321 	         continue;
5322 	
5323 	      consdata = SCIPconsGetData(conss[i]);
5324 	      assert(consdata != NULL);
5325 	
5326 	      /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5327 	      if( SCIPisExprValue(scip, consdata->expr) )
5328 	      {
5329 	         SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5330 	
5331 	         if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5332 	             (!SCIPisInfinity(scip,  consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5333 	         {
5334 	            SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5335 	            *cutoff = TRUE;
5336 	
5337 	            goto TERMINATE;
5338 	         }
5339 	
5340 	         SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5341 	
5342 	         SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5343 	         ++*ndelconss;
5344 	
5345 	         continue;
5346 	      }
5347 	
5348 	      /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5349 	      if( SCIPisExprVar(scip, consdata->expr) )
5350 	      {
5351 	         SCIP_VAR* var;
5352 	         SCIP_Bool tightened;
5353 	
5354 	         var = SCIPgetVarExprVar(consdata->expr);
5355 	         assert(var != NULL);
5356 	
5357 	         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);
5358 	
5359 	         /* ensure that variable bounds are within constraint sides */
5360 	         if( !SCIPisInfinity(scip, -consdata->lhs) )
5361 	         {
5362 	            SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5363 	
5364 	            if( tightened )
5365 	               ++*nchgbds;
5366 	
5367 	            if( *cutoff )
5368 	               goto TERMINATE;
5369 	         }
5370 	
5371 	         if( !SCIPisInfinity(scip, consdata->rhs) )
5372 	         {
5373 	            SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5374 	
5375 	            if( tightened )
5376 	               ++*nchgbds;
5377 	
5378 	            if( *cutoff )
5379 	               goto TERMINATE;
5380 	         }
5381 	
5382 	         /* delete the (now) redundant constraint locally */
5383 	         SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5384 	         ++*ndelconss;
5385 	
5386 	         continue;
5387 	      }
5388 	
5389 	      /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5390 	       * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5391 	       * variable bounds by up to feastol
5392 	       * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5393 	       */
5394 	      SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5395 	      SCIPdebugPrintCons(scip, conss[i], NULL);
5396 	
5397 	      SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5398 	      assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5399 	
5400 	      /* it is unlikely that we detect infeasibility by doing forward propagation */
5401 	      if( *cutoff )
5402 	      {
5403 	         SCIPdebugMsg(scip, " -> cutoff\n");
5404 	         goto TERMINATE;
5405 	      }
5406 	
5407 	      assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5408 	      activity = SCIPexprGetActivity(consdata->expr);
5409 	
5410 	      /* relax sides by feastol
5411 	       * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5412 	       */
5413 	      SCIPintervalSetBounds(&sides,
5414 	         SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5415 	         SCIPisInfinity(scip,  consdata->rhs) ?  SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5416 	
5417 	      if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5418 	      {
5419 	         SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5420 	
5421 	         SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5422 	         ++*ndelconss;
5423 	
5424 	         continue;
5425 	      }
5426 	
5427 	      SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5428 	   }
5429 	
5430 	TERMINATE:
5431 	   /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5432 	   ++conshdlrdata->curboundstag;
5433 	   conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5434 	   conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5435 	   conshdlrdata->intevalvar = intEvalVarBoundTightening;
5436 	
5437 	   return SCIP_OKAY;
5438 	}
5439 	
5440 	/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5441 	static
5442 	SCIP_RETCODE presolveUpgrade(
5443 	   SCIP*                 scip,               /**< SCIP data structure */
5444 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler data structure */
5445 	   SCIP_CONS*            cons,               /**< source constraint to try to convert */
5446 	   SCIP_Bool*            upgraded,           /**< buffer to store whether constraint was upgraded */
5447 	   int*                  nupgdconss,         /**< buffer to increase if constraint was upgraded */
5448 	   int*                  naddconss           /**< buffer to increase with number of additional constraints created during upgrade */
5449 	   )
5450 	{
5451 	   SCIP_CONSHDLRDATA* conshdlrdata;
5452 	   SCIP_CONSDATA* consdata;
5453 	   SCIP_CONS** upgdconss;
5454 	   int upgdconsssize;
5455 	   int nupgdconss_;
5456 	   int i;
5457 	
5458 	   assert(scip != NULL);
5459 	   assert(conshdlr != NULL);
5460 	   assert(cons != NULL);
5461 	   assert(!SCIPconsIsModifiable(cons));
5462 	   assert(upgraded   != NULL);
5463 	   assert(nupgdconss != NULL);
5464 	   assert(naddconss  != NULL);
5465 	
5466 	   *upgraded = FALSE;
5467 	
5468 	   nupgdconss_ = 0;
5469 	
5470 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
5471 	   assert(conshdlrdata != NULL);
5472 	
5473 	   /* if there are no upgrade methods, we can stop */
5474 	   if( conshdlrdata->nconsupgrades == 0 )
5475 	      return SCIP_OKAY;
5476 	
5477 	   upgdconsssize = 2;
5478 	   SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5479 	
5480 	   /* call the upgrading methods */
5481 	   SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5482 	   SCIPdebugPrintCons(scip, cons, NULL);
5483 	
5484 	   consdata = SCIPconsGetData(cons);
5485 	   assert(consdata != NULL);
5486 	
5487 	   /* try all upgrading methods in priority order in case the upgrading step is enable  */
5488 	   for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5489 	   {
5490 	      if( !conshdlrdata->consupgrades[i]->active )
5491 	         continue;
5492 	
5493 	      assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5494 	
5495 	      SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5496 	
5497 	      while( nupgdconss_ < 0 )
5498 	      {
5499 	         /* upgrade function requires more memory: resize upgdconss and call again */
5500 	         assert(-nupgdconss_ > upgdconsssize);
5501 	         upgdconsssize = -nupgdconss_;
5502 	         SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5503 	
5504 	         SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5505 	
5506 	         assert(nupgdconss_ != 0);
5507 	      }
5508 	
5509 	      if( nupgdconss_ > 0 )
5510 	      {
5511 	         /* got upgrade */
5512 	         int j;
5513 	
5514 	         SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5515 	
5516 	         /* add the upgraded constraints to the problem and forget them */
5517 	         for( j = 0; j < nupgdconss_; ++j )
5518 	         {
5519 	            SCIPdebugMsgPrint(scip, "\t");
5520 	            SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5521 	
5522 	            SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) );      /*lint !e613*/
5523 	            SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5524 	         }
5525 	
5526 	         /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5527 	         *nupgdconss += 1;
5528 	         *naddconss += nupgdconss_ - 1;
5529 	         *upgraded = TRUE;
5530 	
5531 	         /* delete upgraded constraint */
5532 	         SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5533 	         SCIP_CALL( SCIPdelCons(scip, cons) );
5534 	
5535 	         break;
5536 	      }
5537 	   }
5538 	
5539 	   SCIPfreeBufferArray(scip, &upgdconss);
5540 	
5541 	   return SCIP_OKAY;
5542 	}
5543 	
5544 	/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5545 	 *  the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5546 	 *  variable bounds, and is not binary
5547 	 */
5548 	static
5549 	SCIP_Bool isSingleLockedCand(
5550 	   SCIP*                 scip,               /**< SCIP data structure */
5551 	   SCIP_EXPR*            expr                /**< variable expression */
5552 	   )
5553 	{
5554 	   SCIP_VAR* var;
5555 	   SCIP_EXPR_OWNERDATA* ownerdata;
5556 	
5557 	   assert(SCIPisExprVar(scip, expr));
5558 	
5559 	   var = SCIPgetVarExprVar(expr);
5560 	   assert(var != NULL);
5561 	
5562 	   ownerdata = SCIPexprGetOwnerData(expr);
5563 	   assert(ownerdata != NULL);
5564 	
5565 	   return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5566 	      && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5567 	      && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5568 	      && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5569 	      && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY
5570 	      && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5571 	}
5572 	
5573 	/** removes all variable expressions that are contained in a given expression from a hash map */
5574 	static
5575 	SCIP_RETCODE removeSingleLockedVars(
5576 	   SCIP*                 scip,               /**< SCIP data structure */
5577 	   SCIP_EXPR*            expr,               /**< expression */
5578 	   SCIP_EXPRITER*        it,                 /**< expression iterator */
5579 	   SCIP_HASHMAP*         exprcands           /**< map to hash variable expressions */
5580 	   )
5581 	{
5582 	   SCIP_EXPR* e;
5583 	
5584 	   for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5585 	   {
5586 	      if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5587 	      {
5588 	         SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5589 	      }
5590 	   }
5591 	
5592 	   return SCIP_OKAY;
5593 	}
5594 	
5595 	/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5596 	 *  nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5597 	 *
5598 	 *  If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5599 	 *  Otherwise, a bound disjunction constraint is added.
5600 	 *
5601 	 *  @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
5602 	 *  @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5603 	 *    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
5604 	 *    on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5605 	 */
5606 	static
5607 	SCIP_RETCODE presolveSingleLockedVars(
5608 	   SCIP*                 scip,               /**< SCIP data structure */
5609 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
5610 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
5611 	   int*                  nchgvartypes,       /**< pointer to store the total number of changed variable types */
5612 	   int*                  naddconss,          /**< pointer to store the total number of added constraints */
5613 	   SCIP_Bool*            infeasible          /**< pointer to store whether problem is infeasible */
5614 	   )
5615 	{
5616 	   SCIP_CONSHDLRDATA* conshdlrdata;
5617 	   SCIP_CONSDATA* consdata;
5618 	   SCIP_EXPR** singlelocked;
5619 	   SCIP_HASHMAP* exprcands;
5620 	   SCIP_Bool hasbounddisj;
5621 	   SCIP_Bool haslhs;
5622 	   SCIP_Bool hasrhs;
5623 	   int nsinglelocked = 0;
5624 	   int i;
5625 	
5626 	   assert(conshdlr != NULL);
5627 	   assert(cons != NULL);
5628 	   assert(nchgvartypes != NULL);
5629 	   assert(naddconss != NULL);
5630 	   assert(infeasible != NULL);
5631 	
5632 	   *nchgvartypes = 0;
5633 	   *naddconss = 0;
5634 	   *infeasible = FALSE;
5635 	
5636 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
5637 	   assert(conshdlrdata != NULL);
5638 	   consdata = SCIPconsGetData(cons);
5639 	   assert(consdata != NULL);
5640 	
5641 	   /* only consider constraints with one finite side */
5642 	   if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5643 	      return SCIP_OKAY;
5644 	
5645 	   /* only consider sum expressions */
5646 	   if( !SCIPisExprSum(scip, consdata->expr) )
5647 	      return SCIP_OKAY;
5648 	
5649 	   /* remember which side is finite */
5650 	   haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5651 	   hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5652 	
5653 	   /* allocate memory */
5654 	   SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5655 	   SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5656 	
5657 	   /* check all variable expressions for single locked variables */
5658 	   for( i = 0; i < consdata->nvarexprs; ++i )
5659 	   {
5660 	      assert(consdata->varexprs[i] != NULL);
5661 	
5662 	      if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5663 	      {
5664 	         SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5665 	         singlelocked[nsinglelocked++] = consdata->varexprs[i];
5666 	      }
5667 	   }
5668 	   SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5669 	
5670 	   if( nsinglelocked > 0 )
5671 	   {
5672 	      SCIP_EXPR** children;
5673 	      SCIP_EXPRITER* it;
5674 	      int nchildren;
5675 	
5676 	      children = SCIPexprGetChildren(consdata->expr);
5677 	      nchildren = SCIPexprGetNChildren(consdata->expr);
5678 	
5679 	      /* create iterator */
5680 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
5681 	      SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
5682 	      SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR);
5683 	
5684 	      for( i = 0; i < nchildren; ++i )
5685 	      {
5686 	         SCIP_EXPR* child;
5687 	         SCIP_Real coef;
5688 	
5689 	         child = children[i];
5690 	         assert(child != NULL);
5691 	         coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5692 	
5693 	         /* ignore linear terms */
5694 	         if( SCIPisExprVar(scip, child) )
5695 	            continue;
5696 	
5697 	         /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5698 	          * expression that represents f_j and remove each variable expression from exprcands
5699 	          */
5700 	         else if( SCIPisExprProduct(scip, child) )
5701 	         {
5702 	            int j;
5703 	
5704 	            for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5705 	            {
5706 	               SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5707 	
5708 	               if( !SCIPisExprVar(scip, grandchild) )
5709 	               {
5710 	                  /* mark all variable expressions that are contained in the expression */
5711 	                  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5712 	               }
5713 	            }
5714 	         }
5715 	         /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5716 	          * for an integer k >= 1
5717 	          */
5718 	         else if( SCIPisExprPower(scip, child) )
5719 	         {
5720 	            SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5721 	            SCIP_Real exponent = SCIPgetExponentExprPow(child);
5722 	            SCIP_Bool valid;
5723 	
5724 	            /* check for even integral exponent */
5725 	            valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5726 	
5727 	            if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5728 	            {
5729 	               /* mark all variable expressions that are contained in the expression */
5730 	               SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5731 	            }
5732 	         }
5733 	         /* all other cases cannot be handled */
5734 	         else
5735 	         {
5736 	            /* mark all variable expressions that are contained in the expression */
5737 	            SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5738 	         }
5739 	      }
5740 	
5741 	      /* free expression iterator */
5742 	      SCIPfreeExpriter(&it);
5743 	   }
5744 	
5745 	   /* check whether the bound disjunction constraint handler is available */
5746 	   hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5747 	
5748 	   /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5749 	   for( i = 0; i < nsinglelocked; ++i )
5750 	   {
5751 	      /* only consider expressions that are still contained in the exprcands map */
5752 	      if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5753 	      {
5754 	         SCIP_CONS* newcons;
5755 	         SCIP_VAR* vars[2];
5756 	         SCIP_BOUNDTYPE boundtypes[2];
5757 	         SCIP_Real bounds[2];
5758 	         char name[SCIP_MAXSTRLEN];
5759 	         SCIP_VAR* var;
5760 	
5761 	         var = SCIPgetVarExprVar(singlelocked[i]);
5762 	         assert(var != NULL);
5763 	         SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5764 	            SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5765 	
5766 	         /* try to change the variable type to binary */
5767 	         if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5768 	         {
5769 	            assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5770 	            SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5771 	            ++(*nchgvartypes);
5772 	
5773 	            if( *infeasible )
5774 	            {
5775 	               SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5776 	               break;
5777 	            }
5778 	         }
5779 	         /* add bound disjunction constraint if bounds of the variable are finite */
5780 	         else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5781 	         {
5782 	            vars[0] = var;
5783 	            vars[1] = var;
5784 	            boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5785 	            boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5786 	            bounds[0] = SCIPvarGetUbGlobal(var);
5787 	            bounds[1] = SCIPvarGetLbGlobal(var);
5788 	
5789 	            SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5790 	
5791 	            /* create, add, and release bound disjunction constraint */
5792 	            (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5793 	            SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5794 	               TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5795 	            SCIP_CALL( SCIPaddCons(scip, newcons) );
5796 	            SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5797 	            ++(*naddconss);
5798 	         }
5799 	      }
5800 	   }
5801 	
5802 	   /* free memory */
5803 	   SCIPfreeBufferArray(scip, &singlelocked);
5804 	   SCIPhashmapFree(&exprcands);
5805 	
5806 	   return SCIP_OKAY;
5807 	}
5808 	
5809 	/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5810 	static
5811 	SCIP_RETCODE presolveImplint(
5812 	   SCIP*                 scip,               /**< SCIP data structure */
5813 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
5814 	   SCIP_CONS**           conss,              /**< nonlinear constraints */
5815 	   int                   nconss,             /**< total number of nonlinear constraints */
5816 	   int*                  nchgvartypes,       /**< pointer to update the total number of changed variable types */
5817 	   SCIP_Bool*            infeasible          /**< pointer to store whether problem is infeasible */
5818 	   )
5819 	{
5820 	   int c;
5821 	
5822 	   assert(scip != NULL);
5823 	   assert(conshdlr != NULL);
5824 	   assert(conss != NULL || nconss == 0);
5825 	   assert(nchgvartypes != NULL);
5826 	   assert(infeasible != NULL);
5827 	
5828 	   *infeasible = FALSE;
5829 	
5830 	   /* nothing can be done if there are no binary and integer variables available */
5831 	   if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5832 	      return SCIP_OKAY;
5833 	
5834 	   /* no continuous var can be made implicit-integer if there are no continuous variables */
5835 	   if( SCIPgetNContVars(scip) == 0 )
5836 	      return SCIP_OKAY;
5837 	
5838 	   for( c = 0; c < nconss; ++c )
5839 	   {
5840 	      SCIP_CONSDATA* consdata;
5841 	      SCIP_EXPR** children;
5842 	      int nchildren;
5843 	      SCIP_Real* coefs;
5844 	      SCIP_EXPR* cand = NULL;
5845 	      SCIP_Real candcoef = 0.0;
5846 	      int i;
5847 	
5848 	      assert(conss != NULL && conss[c] != NULL);
5849 	
5850 	      consdata = SCIPconsGetData(conss[c]);
5851 	      assert(consdata != NULL);
5852 	
5853 	      /* the constraint must be an equality constraint */
5854 	      if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5855 	         continue;
5856 	
5857 	      /* the root expression needs to be a sum expression */
5858 	      if( !SCIPisExprSum(scip, consdata->expr) )
5859 	         continue;
5860 	
5861 	      children = SCIPexprGetChildren(consdata->expr);
5862 	      nchildren = SCIPexprGetNChildren(consdata->expr);
5863 	
5864 	      /* the sum expression must have at least two children
5865 	       * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5866 	       */
5867 	      if( nchildren <= 1 )
5868 	         continue;
5869 	
5870 	      coefs = SCIPgetCoefsExprSum(consdata->expr);
5871 	
5872 	      /* find first continuous variable and get value of its coefficient */
5873 	      for( i = 0; i < nchildren; ++i )
5874 	      {
5875 	         if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5876 	            continue;
5877 	
5878 	         candcoef = coefs[i];
5879 	         assert(candcoef != 0.0);
5880 	
5881 	         /* lhs/rhs - constant divided by candcoef must be integral
5882 	          * if not, break with cand == NULL, so give up
5883 	          */
5884 	         if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5885 	            cand = children[i];
5886 	
5887 	         break;
5888 	      }
5889 	
5890 	      /* no suitable continuous variable found */
5891 	      if( cand == NULL )
5892 	         continue;
5893 	
5894 	      /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5895 	      for( i = 0; i < nchildren; ++i )
5896 	      {
5897 	         if( children[i] == cand )
5898 	            continue;
5899 	
5900 	         /* child i must be integral */
5901 	         if( !SCIPexprIsIntegral(children[i]) )
5902 	         {
5903 	            cand = NULL;
5904 	            break;
5905 	         }
5906 	
5907 	         /* coefficient of child i must be integral if diving by candcoef */
5908 	         if( !SCIPisIntegral(scip, coefs[i] / candcoef) )  /*lint !e414*/
5909 	         {
5910 	            cand = NULL;
5911 	            break;
5912 	         }
5913 	      }
5914 	
5915 	      if( cand == NULL )
5916 	         continue;
5917 	
5918 	      SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5919 	         SCIPvarGetName(SCIPgetVarExprVar(cand)), SCIPconsGetName(conss[c]));
5920 	
5921 	      /* change variable type */
5922 	      SCIP_CALL( SCIPchgVarType(scip, SCIPgetVarExprVar(cand), SCIP_VARTYPE_IMPLINT, infeasible) );
5923 	
5924 	      if( *infeasible )
5925 	         return SCIP_OKAY;
5926 	
5927 	      /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5928 	      SCIPexprSetIntegrality(cand, TRUE);
5929 	   }
5930 	
5931 	   return SCIP_OKAY;
5932 	}
5933 	
5934 	/** creates auxiliary variable for a given expression
5935 	 *
5936 	 * @note for a variable expression it does nothing
5937 	 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5938 	 */
5939 	static
5940 	SCIP_RETCODE createAuxVar(
5941 	   SCIP*                 scip,               /**< SCIP data structure */
5942 	   SCIP_EXPR*            expr                /**< expression */
5943 	   )
5944 	{
5945 	   SCIP_EXPR_OWNERDATA* ownerdata;
5946 	   SCIP_CONSHDLRDATA* conshdlrdata;
5947 	   SCIP_VARTYPE vartype;
5948 	   SCIP_INTERVAL activity;
5949 	   char name[SCIP_MAXSTRLEN];
5950 	
5951 	   assert(scip != NULL);
5952 	   assert(expr != NULL);
5953 	
5954 	   ownerdata = SCIPexprGetOwnerData(expr);
5955 	   assert(ownerdata != NULL);
5956 	   assert(ownerdata->nauxvaruses > 0);
5957 	
5958 	   /* if we already have auxvar, then do nothing */
5959 	   if( ownerdata->auxvar != NULL )
5960 	      return SCIP_OKAY;
5961 	
5962 	   /* if expression is a variable-expression, then do nothing */
5963 	   if( SCIPisExprVar(scip, expr) )
5964 	      return SCIP_OKAY;
5965 	
5966 	   if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
5967 	   {
5968 	      SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
5969 	      return SCIP_INVALIDCALL;
5970 	   }
5971 	
5972 	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
5973 	   assert(conshdlrdata != NULL);
5974 	   assert(conshdlrdata->auxvarid >= 0);
5975 	
5976 	   /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
5977 	    * but it usually indicates a missing simplify
5978 	    * if we find situations where we need to have an auxvar for a constant, then remove this assert
5979 	    */
5980 	   assert(!SCIPisExprValue(scip, expr));
5981 	
5982 	   /* create and capture auxiliary variable */
5983 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
5984 	   ++conshdlrdata->auxvarid;
5985 	
5986 	   /* type of auxiliary variable depends on integrality information of the expression */
5987 	   vartype = SCIPexprIsIntegral(expr) ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS;
5988 	
5989 	   /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
5990 	   if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
5991 	   {
5992 	      activity = SCIPexprGetActivity(expr);
5993 	      /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
5994 	       * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
5995 	       * and abort in debug mode only
5996 	       */
5997 	      if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity) )
5998 	      {
5999 	         SCIPABORT();
6000 	         SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
6001 	      }
6002 	   }
6003 	   else
6004 	      SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
6005 	
6006 	   /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6007 	    * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6008 	    */
6009 	   if( SCIPgetDepth(scip) == 0 )
6010 	   {
6011 	      SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
6012 	   }
6013 	   else
6014 	   {
6015 	      SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
6016 	   }
6017 	
6018 	   /* mark the auxiliary variable to be added for the relaxation only
6019 	    * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6020 	    * or to copy the variable to a subscip
6021 	    */
6022 	   SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6023 	
6024 	   SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6025 	
6026 	   SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6027 	
6028 	   /* add variable locks in both directions
6029 	    * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6030 	    *   but then we need to also update the auxvars locks when the expr locks change
6031 	    */
6032 	   SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6033 	
6034 	#ifdef WITH_DEBUG_SOLUTION
6035 	   if( SCIPdebugIsMainscip(scip) )
6036 	   {
6037 	      /* store debug solution value of auxiliary variable
6038 	       * assumes that expression has been evaluated in debug solution before
6039 	       */
6040 	      SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6041 	   }
6042 	#endif
6043 	
6044 	   if( SCIPgetDepth(scip) > 0 )
6045 	   {
6046 	      /* initialize local bounds to (locally valid) activity */
6047 	      SCIP_Bool cutoff;
6048 	      SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6049 	      assert(!cutoff);  /* should not happen as activity wasn't empty and variable is new */
6050 	   }
6051 	
6052 	   return SCIP_OKAY;
6053 	}
6054 	
6055 	/** initializes separation for constraint
6056 	 *
6057 	 * - ensures that activities are up to date in all expressions
6058 	 * - creates auxiliary variables where required
6059 	 * - calls propExprDomains() to possibly tighten auxvar bounds
6060 	 * - calls separation initialization callback of nlhdlrs
6061 	 */
6062 	static
6063 	SCIP_RETCODE initSepa(
6064 	   SCIP*                 scip,               /**< SCIP data structure */
6065 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6066 	   SCIP_CONS**           conss,              /**< constraints */
6067 	   int                   nconss,             /**< number of constraints */
6068 	   SCIP_Bool*            infeasible          /**< pointer to store whether the problem is infeasible or not */
6069 	   )
6070 	{
6071 	   SCIP_CONSDATA* consdata;
6072 	   SCIP_CONSHDLRDATA* conshdlrdata;
6073 	   SCIP_EXPRITER* it;
6074 	   SCIP_EXPR* expr;
6075 	   SCIP_RESULT result;
6076 	   SCIP_VAR* auxvar;
6077 	   int nreductions = 0;
6078 	   int c, e;
6079 	
6080 	   assert(scip != NULL);
6081 	   assert(conshdlr != NULL);
6082 	   assert(conss != NULL || nconss == 0);
6083 	   assert(nconss >= 0);
6084 	   assert(infeasible != NULL);
6085 	
6086 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6087 	   assert(conshdlrdata != NULL);
6088 	
6089 	   /* start with new propbounds (just to be sure, should not be needed) */
6090 	   ++conshdlrdata->curpropboundstag;
6091 	
6092 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6093 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6094 	
6095 	   /* first ensure activities are up to date and create auxvars */
6096 	   *infeasible = FALSE;
6097 	   for( c = 0; c < nconss; ++c )
6098 	   {
6099 	      assert(conss != NULL);
6100 	      assert(conss[c] != NULL);
6101 	
6102 	      consdata = SCIPconsGetData(conss[c]);
6103 	      assert(consdata != NULL);
6104 	      assert(consdata->expr != NULL);
6105 	
6106 	#ifdef WITH_DEBUG_SOLUTION
6107 	      if( SCIPdebugIsMainscip(scip) )
6108 	      {
6109 	         SCIP_SOL* debugsol;
6110 	
6111 	         SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6112 	
6113 	         if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6114 	         {
6115 	            /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6116 	             * in createAuxVar()
6117 	             */
6118 	            SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6119 	         }
6120 	      }
6121 	#endif
6122 	
6123 	      /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6124 	      SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6125 	
6126 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6127 	      {
6128 	         if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6129 	         {
6130 	            SCIP_CALL( createAuxVar(scip, expr) );
6131 	         }
6132 	      }
6133 	
6134 	      auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6135 	      if( auxvar != NULL )
6136 	      {
6137 	         SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6138 	               SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6139 	         /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6140 	         SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6141 	         if( *infeasible )
6142 	         {
6143 	            SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6144 	            break;
6145 	         }
6146 	
6147 	         SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6148 	         if( *infeasible )
6149 	         {
6150 	            SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6151 	            break;
6152 	         }
6153 	      }
6154 	   }
6155 	
6156 	   /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6157 	    * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6158 	    * (e.g., log(x*y), which becomes log(w), w=x*y
6159 	    *  log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6160 	    */
6161 	   SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6162 	   if( result == SCIP_CUTOFF )
6163 	      *infeasible = TRUE;
6164 	
6165 	   /* now call initsepa of nlhdlrs
6166 	    * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6167 	    *   but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6168 	    */
6169 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6170 	   for( c = 0; c < nconss && !*infeasible; ++c )
6171 	   {
6172 	      assert(conss != NULL);
6173 	      assert(conss[c] != NULL);
6174 	
6175 	      consdata = SCIPconsGetData(conss[c]);
6176 	      assert(consdata != NULL);
6177 	      assert(consdata->expr != NULL);
6178 	
6179 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6180 	      {
6181 	         SCIP_EXPR_OWNERDATA* ownerdata;
6182 	
6183 	         ownerdata = SCIPexprGetOwnerData(expr);
6184 	         assert(ownerdata != NULL);
6185 	
6186 	         if( ownerdata->nauxvaruses == 0 )
6187 	            continue;
6188 	
6189 	         for( e = 0; e < ownerdata->nenfos; ++e )
6190 	         {
6191 	            SCIP_NLHDLR* nlhdlr;
6192 	            SCIP_Bool underestimate;
6193 	            SCIP_Bool overestimate;
6194 	            assert(ownerdata->enfos[e] != NULL);
6195 	
6196 	            /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6197 	             * which participated in a previous initSepa() call
6198 	             */
6199 	            if( ownerdata->enfos[e]->issepainit )
6200 	               continue;
6201 	
6202 	            /* only call initsepa if it will actually separate */
6203 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6204 	               continue;
6205 	
6206 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
6207 	            assert(nlhdlr != NULL);
6208 	
6209 	            /* only init sepa if there is an initsepa callback */
6210 	            if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6211 	               continue;
6212 	
6213 	            /* check whether expression needs to be under- or overestimated */
6214 	            overestimate = ownerdata->nlocksneg > 0;
6215 	            underestimate = ownerdata->nlockspos > 0;
6216 	            assert(underestimate || overestimate);
6217 	
6218 	            SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6219 	
6220 	            /* call the separation initialization callback of the nonlinear handler */
6221 	            SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6222 	               ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6223 	            ownerdata->enfos[e]->issepainit = TRUE;
6224 	
6225 	            if( *infeasible )
6226 	            {
6227 	               /* stop everything if we detected infeasibility */
6228 	               SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6229 	               break;
6230 	            }
6231 	         }
6232 	      }
6233 	   }
6234 	
6235 	   SCIPfreeExpriter(&it);
6236 	
6237 	   return SCIP_OKAY;
6238 	}
6239 	
6240 	/** returns whether we are ok to branch on auxiliary variables
6241 	 *
6242 	 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6243 	 */
6244 	static
6245 	SCIP_Bool branchAuxNonlinear(
6246 	   SCIP*                 scip,               /**< SCIP data structure */
6247 	   SCIP_CONSHDLR*        conshdlr            /**< constraint handler */
6248 	   )
6249 	{
6250 	   SCIP_CONSHDLRDATA* conshdlrdata;
6251 	
6252 	   assert(conshdlr != NULL);
6253 	
6254 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6255 	   assert(conshdlrdata != NULL);
6256 	
6257 	   return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6258 	}
6259 	
6260 	/** gets weight of variable when splitting violation score onto several variables in an expression */
6261 	static
6262 	SCIP_Real getViolSplitWeight(
6263 	   SCIP*                 scip,               /**< SCIP data structure */
6264 	   SCIP_CONSHDLR*        conshdlr,           /**< expr constraint handler */
6265 	   SCIP_VAR*             var,                /**< variable */
6266 	   SCIP_SOL*             sol                 /**< current solution */
6267 	   )
6268 	{
6269 	   SCIP_CONSHDLRDATA* conshdlrdata;
6270 	
6271 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6272 	   assert(conshdlrdata != NULL);
6273 	
6274 	   switch( conshdlrdata->branchviolsplit )
6275 	   {
6276 	      case 'u' :  /* uniform: everyone gets the same score */
6277 	         return 1.0;
6278 	
6279 	      case 'm' :  /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6280 	      {
6281 	         SCIP_Real weight;
6282 	         weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6283 	         return MAX(0.05, weight);
6284 	      }
6285 	
6286 	      case 'd' :  /* domain width */
6287 	         return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6288 	
6289 	      case 'l' :  /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6290 	      {
6291 	         SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6292 	         assert(width > 0.0);
6293 	         if( width > 10.0 )
6294 	            return 10.0*log10(width);
6295 	         if( width < 0.1 )
6296 	            return 0.1/(-log10(width));
6297 	         return width;
6298 	      }
6299 	
6300 	      default :
6301 	         SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6302 	         SCIPABORT();
6303 	         return SCIP_INVALID;
6304 	   }
6305 	}
6306 	
6307 	/** adds violation-branching score to a set of expressions, thereby distributing the score
6308 	 *
6309 	 * Each expression must either be a variable expression or have an aux-variable.
6310 	 *
6311 	 * If unbounded variables are present, each unbounded var gets an even score.
6312 	 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6313 	 */
6314 	static
6315 	void addExprsViolScore(
6316 	   SCIP*                 scip,               /**< SCIP data structure */
6317 	   SCIP_EXPR**           exprs,              /**< expressions where to add branching score */
6318 	   int                   nexprs,             /**< number of expressions */
6319 	   SCIP_Real             violscore,          /**< violation-branching score to add to expression */
6320 	   SCIP_SOL*             sol,                /**< current solution */
6321 	   SCIP_Bool*            success             /**< buffer to store whether at least one violscore was added */
6322 	   )
6323 	{
6324 	   SCIP_CONSHDLR* conshdlr;
6325 	   SCIP_VAR* var;
6326 	   SCIP_Real weight;
6327 	   SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6328 	   int nunbounded = 0;  /* number of candidates with unbounded domain */
6329 	   int i;
6330 	
6331 	   assert(exprs != NULL);
6332 	   assert(nexprs > 0);
6333 	   assert(success != NULL);
6334 	
6335 	   if( nexprs == 1 )
6336 	   {
6337 	      SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6338 	      SCIPdebug( var = SCIPgetExprAuxVarNonlinear(exprs[0]); )
6339 	      SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6340 	         SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6341 	      *success = TRUE;
6342 	      return;
6343 	   }
6344 	
6345 	   conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6346 	
6347 	   for( i = 0; i < nexprs; ++i )
6348 	   {
6349 	      var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6350 	      assert(var != NULL);
6351 	
6352 	      if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6353 	         ++nunbounded;
6354 	      else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6355 	         weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6356 	   }
6357 	
6358 	   *success = FALSE;
6359 	   for( i = 0; i < nexprs; ++i )
6360 	   {
6361 	      var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6362 	      assert(var != NULL);
6363 	
6364 	      if( nunbounded > 0 )
6365 	      {
6366 	         if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6367 	         {
6368 	            SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6369 	            SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6370 	               100.0/nunbounded, violscore,
6371 	               SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6372 	            *success = TRUE;
6373 	         }
6374 	      }
6375 	      else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6376 	      {
6377 	         assert(weightsum > 0.0);
6378 	
6379 	         weight = getViolSplitWeight(scip, conshdlr, var, sol);
6380 	         SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6381 	         SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6382 	            100*weight / weightsum, violscore,
6383 	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6384 	         *success = TRUE;
6385 	      }
6386 	      else
6387 	      {
6388 	         SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6389 	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6390 	      }
6391 	   }
6392 	}
6393 	
6394 	/** adds violation-branching score to children of expression for given auxiliary variables
6395 	 *
6396 	 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6397 	 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6398 	 *
6399 	 * @note This method may modify the given auxvars array by means of sorting.
6400 	 */
6401 	static
6402 	SCIP_RETCODE addExprViolScoresAuxVars(
6403 	   SCIP*                 scip,               /**< SCIP data structure */
6404 	   SCIP_EXPR*            expr,               /**< expression where to start searching */
6405 	   SCIP_Real             violscore,          /**< violation score to add to expression */
6406 	   SCIP_VAR**            auxvars,            /**< auxiliary variables for which to find expression */
6407 	   int                   nauxvars,           /**< number of auxiliary variables */
6408 	   SCIP_SOL*             sol,                /**< current solution (NULL for the LP solution) */
6409 	   SCIP_Bool*            success             /**< buffer to store whether at least one violscore was added */
6410 	   )
6411 	{
6412 	   SCIP_EXPRITER* it;
6413 	   SCIP_VAR* auxvar;
6414 	   SCIP_EXPR** exprs;
6415 	   int nexprs;
6416 	   int pos;
6417 	
6418 	   assert(scip != NULL);
6419 	   assert(expr != NULL);
6420 	   assert(auxvars != NULL);
6421 	   assert(success != NULL);
6422 	
6423 	   /* sort variables to make lookup below faster */
6424 	   SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6425 	
6426 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6427 	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_BFS, FALSE) );
6428 	
6429 	   SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6430 	   nexprs = 0;
6431 	
6432 	   for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6433 	   {
6434 	      auxvar = SCIPgetExprAuxVarNonlinear(expr);
6435 	      if( auxvar == NULL )
6436 	         continue;
6437 	
6438 	      /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6439 	      if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6440 	      {
6441 	         assert(auxvars[pos] == auxvar);
6442 	
6443 	         SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6444 	         exprs[nexprs++] = expr;
6445 	
6446 	         if( nexprs == nauxvars )
6447 	            break;
6448 	      }
6449 	   }
6450 	
6451 	   SCIPfreeExpriter(&it);
6452 	
6453 	   if( nexprs > 0 )
6454 	   {
6455 	      SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6456 	   }
6457 	   else
6458 	      *success = FALSE;
6459 	
6460 	   SCIPfreeBufferArray(scip, &exprs);
6461 	
6462 	   return SCIP_OKAY;
6463 	}
6464 	
6465 	/** registers all unfixed variables in violated constraints as branching candidates */
6466 	static
6467 	SCIP_RETCODE registerBranchingCandidatesAllUnfixed(
6468 	   SCIP*                 scip,               /**< SCIP data structure */
6469 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6470 	   SCIP_CONS**           conss,              /**< constraints */
6471 	   int                   nconss,             /**< number of constraints */
6472 	   int*                  nnotify             /**< counter for number of notifications performed */
6473 	   )
6474 	{
6475 	   SCIP_CONSDATA* consdata;
6476 	   SCIP_VAR* var;
6477 	   int c;
6478 	   int i;
6479 	
6480 	   assert(conshdlr != NULL);
6481 	   assert(conss != NULL || nconss == 0);
6482 	   assert(nnotify != NULL);
6483 	
6484 	   *nnotify = 0;
6485 	
6486 	   for( c = 0; c < nconss; ++c )
6487 	   {
6488 	      assert(conss != NULL && conss[c] != NULL);
6489 	
6490 	      consdata = SCIPconsGetData(conss[c]);
6491 	      assert(consdata != NULL);
6492 	
6493 	      /* consider only violated constraints */
6494 	      if( !isConsViolated(scip, conss[c]) )
6495 	         continue;
6496 	
6497 	      /* register all variables that have not been fixed yet */
6498 	      assert(consdata->varexprs != NULL);
6499 	      for( i = 0; i < consdata->nvarexprs; ++i )
6500 	      {
6501 	         var = SCIPgetVarExprVar(consdata->varexprs[i]);
6502 	         assert(var != NULL);
6503 	
6504 	         if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6505 	         {
6506 	            SCIP_CALL( SCIPaddExternBranchCand(scip, var, getConsAbsViolation(conss[c]), SCIP_INVALID) );
6507 	            ++(*nnotify);
6508 	         }
6509 	      }
6510 	   }
6511 	
6512 	   return SCIP_OKAY;
6513 	}
6514 	
6515 	/** registers all variables in violated constraints with branching scores as external branching candidates */
6516 	static
6517 	SCIP_RETCODE registerBranchingCandidates(
6518 	   SCIP*                 scip,               /**< SCIP data structure */
6519 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6520 	   SCIP_CONS**           conss,              /**< constraints */
6521 	   int                   nconss,             /**< number of constraints */
6522 	   SCIP_Bool*            success             /**< buffer to store whether at least one branching candidate was added */
6523 	   )
6524 	{
6525 	   SCIP_CONSDATA* consdata;
6526 	   SCIP_EXPRITER* it = NULL;
6527 	   int c;
6528 	
6529 	   assert(conshdlr != NULL);
6530 	   assert(success != NULL);
6531 	
6532 	   *success = FALSE;
6533 	
6534 	   if( branchAuxNonlinear(scip, conshdlr) )
6535 	   {
6536 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6537 	      SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6538 	   }
6539 	
6540 	   /* register external branching candidates */
6541 	   for( c = 0; c < nconss; ++c )
6542 	   {
6543 	      assert(conss != NULL && conss[c] != NULL);
6544 	
6545 	      consdata = SCIPconsGetData(conss[c]);
6546 	      assert(consdata != NULL);
6547 	      assert(consdata->varexprs != NULL);
6548 	
6549 	      /* consider only violated constraints */
6550 	      if( !isConsViolated(scip, conss[c]) )
6551 	         continue;
6552 	
6553 	      if( !branchAuxNonlinear(scip, conshdlr) )
6554 	      {
6555 	         int i;
6556 	
6557 	         /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6558 	          * only, so we can loop over variable expressions
6559 	          */
6560 	         for( i = 0; i < consdata->nvarexprs; ++i )
6561 	         {
6562 	            SCIP_Real violscore;
6563 	            SCIP_Real lb;
6564 	            SCIP_Real ub;
6565 	            SCIP_VAR* var;
6566 	
6567 	            violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6568 	
6569 	            /* skip variable expressions that do not have a violation score */
6570 	            if( violscore == 0.0 )
6571 	               continue;
6572 	
6573 	            var = SCIPgetVarExprVar(consdata->varexprs[i]);
6574 	            assert(var != NULL);
6575 	
6576 	            lb = SCIPvarGetLbLocal(var);
6577 	            ub = SCIPvarGetUbLocal(var);
6578 	
6579 	            /* consider variable for branching if it has not been fixed yet */
6580 	            if( !SCIPisEQ(scip, lb, ub) )
6581 	            {
6582 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6583 	               SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6584 	               *success = TRUE;
6585 	            }
6586 	            else
6587 	            {
6588 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6589 	            }
6590 	
6591 	            /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6592 	             * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6593 	             */
6594 	            SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6595 	         }
6596 	      }
6597 	      else
6598 	      {
6599 	         SCIP_EXPR* expr;
6600 	         SCIP_VAR* var;
6601 	         SCIP_Real lb;
6602 	         SCIP_Real ub;
6603 	         SCIP_Real violscore;
6604 	
6605 	         for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6606 	         {
6607 	            violscore = SCIPgetExprViolScoreNonlinear(expr);
6608 	            if( violscore == 0.0 )
6609 	               continue;
6610 	
6611 	            /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6612 	             * variable, so this expression should either be an original variable or have an auxiliary variable
6613 	             */
6614 	            var = SCIPgetExprAuxVarNonlinear(expr);
6615 	            assert(var != NULL);
6616 	
6617 	            lb = SCIPvarGetLbLocal(var);
6618 	            ub = SCIPvarGetUbLocal(var);
6619 	
6620 	            /* consider variable for branching if it has not been fixed yet */
6621 	            if( !SCIPisEQ(scip, lb, ub) )
6622 	            {
6623 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6624 	
6625 	               SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6626 	               *success = TRUE;
6627 	            }
6628 	            else
6629 	            {
6630 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6631 	            }
6632 	         }
6633 	      }
6634 	   }
6635 	
6636 	   if( it != NULL )
6637 	      SCIPfreeExpriter(&it);
6638 	
6639 	   return SCIP_OKAY;
6640 	}
6641 	
6642 	/** collect branching candidates from violated constraints
6643 	 *
6644 	 * Fills array with expressions that serve as branching candidates.
6645 	 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6646 	 * branching candidate.
6647 	 *
6648 	 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6649 	 * through variable-expressions only.
6650 	 */
6651 	static
6652 	SCIP_RETCODE collectBranchingCandidates(
6653 	   SCIP*                 scip,               /**< SCIP data structure */
6654 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6655 	   SCIP_CONS**           conss,              /**< constraints to process */
6656 	   int                   nconss,             /**< number of constraints */
6657 	   SCIP_Real             maxrelconsviol,     /**< maximal scaled constraint violation */
6658 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
6659 	   SCIP_Longint          soltag,             /**< tag of solution */
6660 	   BRANCHCAND*           cands,              /**< array where to store candidates, must be at least SCIPgetNVars() long */
6661 	   int*                  ncands              /**< number of candidates found */
6662 	   )
6663 	{
6664 	   SCIP_CONSHDLRDATA* conshdlrdata;
6665 	   SCIP_CONSDATA* consdata;
6666 	   SCIP_EXPRITER* it = NULL;
6667 	   int c;
6668 	   int attempt;
6669 	   SCIP_VAR* var;
6670 	
6671 	   assert(scip != NULL);
6672 	   assert(conshdlr != NULL);
6673 	   assert(cands != NULL);
6674 	   assert(ncands != NULL);
6675 	
6676 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6677 	   assert(conshdlrdata != NULL);
6678 	
6679 	   if( branchAuxNonlinear(scip, conshdlr) )
6680 	   {
6681 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6682 	      SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6683 	   }
6684 	
6685 	   *ncands = 0;
6686 	   for( attempt = 0; attempt < 2; ++attempt )
6687 	   {
6688 	      /* collect branching candidates from violated constraints
6689 	       * in the first attempt, consider only constraints with large violation
6690 	       * in the second attempt, consider all remaining violated constraints
6691 	       */
6692 	      for( c = 0; c < nconss; ++c )
6693 	      {
6694 	         SCIP_Real consviol;
6695 	
6696 	         assert(conss != NULL && conss[c] != NULL);
6697 	
6698 	         /* consider only violated constraints */
6699 	         if( !isConsViolated(scip, conss[c]) )
6700 	            continue;
6701 	
6702 	         consdata = SCIPconsGetData(conss[c]);
6703 	         assert(consdata != NULL);
6704 	         assert(consdata->varexprs != NULL);
6705 	
6706 	         SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6707 	
6708 	         if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6709 	            continue;
6710 	         else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6711 	            continue;
6712 	
6713 	         if( !branchAuxNonlinear(scip, conshdlr) )
6714 	         {
6715 	            int i;
6716 	
6717 	            /* if not branching on auxvars, then violation-branching scores will be available for original variables
6718 	             * only, so we can loop over variable expressions
6719 	             * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6720 	             * variable, therefore we invalidate the score of a variable after processing it.
6721 	             */
6722 	            for( i = 0; i < consdata->nvarexprs; ++i )
6723 	            {
6724 	               SCIP_Real lb;
6725 	               SCIP_Real ub;
6726 	
6727 	               /* skip variable expressions that do not have a valid violation score */
6728 	               if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6729 	                  continue;
6730 	
6731 	               var = SCIPgetVarExprVar(consdata->varexprs[i]);
6732 	               assert(var != NULL);
6733 	
6734 	               lb = SCIPvarGetLbLocal(var);
6735 	               ub = SCIPvarGetUbLocal(var);
6736 	
6737 	               /* skip already fixed variable */
6738 	               if( SCIPisEQ(scip, lb, ub) )
6739 	               {
6740 	                  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6741 	                  continue;
6742 	               }
6743 	
6744 	               assert(*ncands + 1 < SCIPgetNVars(scip));
6745 	               cands[*ncands].expr = consdata->varexprs[i];
6746 	               cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6747 	               ++(*ncands);
6748 	
6749 	               /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6750 	                * several times as external branching candidate */
6751 	               SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6752 	            }
6753 	         }
6754 	         else
6755 	         {
6756 	            SCIP_EXPR* expr;
6757 	            SCIP_Real lb;
6758 	            SCIP_Real ub;
6759 	
6760 	            for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6761 	            {
6762 	               if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6763 	                  continue;
6764 	
6765 	               /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6766 	                * variables, so this expression should either be an original variable or have an auxiliary variable
6767 	                */
6768 	               var = SCIPgetExprAuxVarNonlinear(expr);
6769 	               assert(var != NULL);
6770 	
6771 	               lb = SCIPvarGetLbLocal(var);
6772 	               ub = SCIPvarGetUbLocal(var);
6773 	
6774 	               /* skip already fixed variable */
6775 	               if( SCIPisEQ(scip, lb, ub) )
6776 	               {
6777 	                  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6778 	                  continue;
6779 	               }
6780 	
6781 	               assert(*ncands + 1 < SCIPgetNVars(scip));
6782 	               cands[*ncands].expr = expr;
6783 	               cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6784 	               ++(*ncands);
6785 	            }
6786 	         }
6787 	      }
6788 	
6789 	      /* if we have branching candidates, then we don't need another attempt */
6790 	      if( *ncands > 0 )
6791 	         break;
6792 	   }
6793 	
6794 	   if( it != NULL )
6795 	      SCIPfreeExpriter(&it);
6796 	
6797 	   return SCIP_OKAY;
6798 	}
6799 	
6800 	/** computes a branching score for a variable that reflects how important branching on this variable would be for
6801 	 * improving the dual bound from the LP relaxation
6802 	 *
6803 	 * Assume the Lagrangian for the current LP is something of the form
6804 	 *   L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6805 	 * where x are the original variables, z the auxiliary variables,
6806 	 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6807 	 *
6808 	 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6809 	 * If we could have used not only an estimator, but the actual function f(x), then this would
6810 	 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6811 	 * Using a lot of handwaving, we claim that
6812 	 *   lambda_i * (f(x) - a_i'x + b_i)
6813 	 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6814 	 * If an estimator depended on local bounds, then it could be improved by branching.
6815 	 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6816 	 *
6817 	 * 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.
6818 	 * To scale, we divide by the LP objective value (if >1).
6819 	 *
6820 	 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6821 	 *     these are affected by the bounds on original variables indirectly (through forward-propagation)
6822 	 *
6823 	 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6824 	 *     in effect, we should go from the row to the expression for which it was generated and consider only variables that
6825 	 *     would also be branching candidates
6826 	 */
6827 	static
6828 	SCIP_Real getDualBranchscore(
6829 	   SCIP*                 scip,               /**< SCIP data structure */
6830 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6831 	   SCIP_VAR*             var                 /**< variable */
6832 	   )
6833 	{
6834 	   SCIP_COL* col;
6835 	   SCIP_ROW** rows;
6836 	   int nrows;
6837 	   int r;
6838 	   SCIP_Real dualscore;
6839 	
6840 	   assert(scip != NULL);
6841 	   assert(conshdlr != NULL);
6842 	   assert(var != NULL);
6843 	
6844 	   /* if LP not solved, then the dual branching score is not available */
6845 	   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
6846 	      return 0.0;
6847 	
6848 	   /* if var is not in the LP, then the dual branching score is not available */
6849 	   if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
6850 	      return 0.0;
6851 	
6852 	   col = SCIPvarGetCol(var);
6853 	   assert(col != NULL);
6854 	
6855 	   if( !SCIPcolIsInLP(col) )
6856 	      return 0.0;
6857 	
6858 	   nrows = SCIPcolGetNLPNonz(col);  /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6859 	   rows = SCIPcolGetRows(col);
6860 	
6861 	   /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6862 	
6863 	   /* aggregate duals from all rows from consexpr with non-zero dual
6864 	    * TODO: this is a quick-and-dirty implementation, and not used by default
6865 	    *   in the long run, this should be either removed or replaced by a proper implementation
6866 	    */
6867 	   dualscore = 0.0;
6868 	   for( r = 0; r < nrows; ++r )
6869 	   {
6870 	      SCIP_Real estimategap;
6871 	      const char* estimategapstr;
6872 	
6873 	      /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6874 	       * these would typically be local, unless they are created at the root node
6875 	       * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6876 	      if( !SCIProwIsLocal(rows[r]) )
6877 	         continue;
6878 	       */
6879 	      if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6880 	         continue;
6881 	      if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6882 	         continue;
6883 	
6884 	      estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6885 	      if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6886 	         continue;
6887 	      estimategap = atof(estimategapstr + 13);
6888 	      assert(estimategap >= 0.0);
6889 	      if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6890 	         estimategap = SCIPgetHugeValue(scip);
6891 	
6892 	      /* SCIPinfoMessage(scip, enfologfile, "  row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6893 	      SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6894 	
6895 	      dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6896 	   }
6897 	
6898 	   /* divide by optimal value of LP for scaling */
6899 	   dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6900 	
6901 	   return dualscore;
6902 	}
6903 	
6904 	/** computes branching scores (including weighted score) for a set of candidates
6905 	 *
6906 	 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6907 	 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6908 	 *
6909 	 * For each score, compute the maximum over all candidates.
6910 	 *
6911 	 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6912 	 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6913 	 * score of all candidates.
6914 	 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6915 	 *
6916 	 * For example:
6917 	 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6918 	 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6919 	 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6920 	 * - 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.
6921 	 *   The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6922 	 */
6923 	static
6924 	void scoreBranchingCandidates(
6925 	   SCIP*                 scip,               /**< SCIP data structure */
6926 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6927 	   BRANCHCAND*           cands,              /**< branching candidates */
6928 	   int                   ncands,             /**< number of candidates */
6929 	   SCIP_SOL*             sol                 /**< solution to enforce (NULL for the LP solution) */
6930 	   )
6931 	{
6932 	   SCIP_CONSHDLRDATA* conshdlrdata;
6933 	   BRANCHCAND maxscore;
6934 	   int c;
6935 	
6936 	   assert(scip != NULL);
6937 	   assert(conshdlr != NULL);
6938 	   assert(cands != NULL);
6939 	   assert(ncands > 0);
6940 	
6941 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6942 	   assert(conshdlrdata != NULL);
6943 	
6944 	   /* initialize counts to 0 */
6945 	   memset(&maxscore, 0, sizeof(BRANCHCAND));
6946 	
6947 	   for( c = 0; c < ncands; ++c )
6948 	   {
6949 	      if( conshdlrdata->branchviolweight > 0.0 )
6950 	      {
6951 	         /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6952 	         maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6953 	      }
6954 	
6955 	      if( conshdlrdata->branchdomainweight > 0.0 )
6956 	      {
6957 	         SCIP_Real domainwidth;
6958 	         SCIP_VAR* var;
6959 	
6960 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6961 	         assert(var != NULL);
6962 	
6963 	         /* get domain width, taking infinity at 1e20 on purpose */
6964 	         domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6965 	
6966 	         /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6967 	          * and log(2 * infinity *  MAX(epsilon, domainwidth)) for domain width < 1
6968 	          * the idea is to penalize very large and very small domains
6969 	          */
6970 	         if( domainwidth >= 1.0 )
6971 	            cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
6972 	         else
6973 	            cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
6974 	
6975 	         maxscore.domain = MAX(cands[c].domain, maxscore.domain);
6976 	      }
6977 	      else
6978 	         cands[c].domain = 0.0;
6979 	
6980 	      if( conshdlrdata->branchdualweight > 0.0 )
6981 	      {
6982 	         SCIP_VAR* var;
6983 	
6984 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6985 	         assert(var != NULL);
6986 	
6987 	         cands[c].dual = getDualBranchscore(scip, conshdlr, var);
6988 	         maxscore.dual = MAX(cands[c].dual, maxscore.dual);
6989 	      }
6990 	
6991 	      if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
6992 	      {
6993 	         SCIP_VAR* var;
6994 	
6995 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6996 	         assert(var != NULL);
6997 	
6998 	         if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6999 	            cands[c].pscost = SCIP_INVALID;
7000 	         else
7001 	         {
7002 	            SCIP_Real brpoint;
7003 	            SCIP_Real pscostdown;
7004 	            SCIP_Real pscostup;
7005 	            char strategy;
7006 	
7007 	            /* decide how to compute pseudo-cost scores
7008 	             * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7009 	             * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7010 	             */
7011 	            if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
7012 	               strategy = conshdlrdata->branchpscostupdatestrategy;
7013 	            else
7014 	               strategy = 'l';
7015 	
7016 	            brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7017 	
7018 	            /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7019 	             * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7020 	             * For here, I use a simple #counts >= branchpscostreliable.
7021 	             * TODO use SCIPgetVarPseudocostCount() instead?
7022 	             */
7023 	            if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7024 	            {
7025 	               switch( strategy )
7026 	               {
7027 	                  case 's' :
7028 	                     pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7029 	                     break;
7030 	                  case 'd' :
7031 	                     pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7032 	                     break;
7033 	                  case 'l' :
7034 	                     if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7035 	                        pscostdown = SCIP_INVALID;
7036 	                     else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7037 	                        pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7038 	                     else
7039 	                        pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, NULL, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7040 	                     break;
7041 	                  default :
7042 	                     SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7043 	                     pscostdown = SCIP_INVALID;
7044 	               }
7045 	            }
7046 	            else
7047 	               pscostdown = SCIP_INVALID;
7048 	
7049 	            if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7050 	            {
7051 	               switch( strategy )
7052 	               {
7053 	                  case 's' :
7054 	                     pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7055 	                     break;
7056 	                  case 'd' :
7057 	                     pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7058 	                     break;
7059 	                  case 'l' :
7060 	                     if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7061 	                        pscostup = SCIP_INVALID;
7062 	                     else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7063 	                        pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7064 	                     else
7065 	                        pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, NULL, var) );
7066 	                     break;
7067 	                  default :
7068 	                     SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7069 	                     pscostup = SCIP_INVALID;
7070 	               }
7071 	            }
7072 	            else
7073 	               pscostup = SCIP_INVALID;
7074 	
7075 	            /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7076 	             * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7077 	             */
7078 	            if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7079 	               cands[c].pscost = SCIP_INVALID;
7080 	            else if( pscostdown == SCIP_INVALID )
7081 	               cands[c].pscost = pscostup;
7082 	            else if( pscostup == SCIP_INVALID )
7083 	               cands[c].pscost = pscostdown;
7084 	            else
7085 	               cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup);  /* pass NULL for var to avoid multiplication with branch-factor */
7086 	         }
7087 	
7088 	         if( cands[c].pscost != SCIP_INVALID )
7089 	            maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7090 	      }
7091 	
7092 	      if( conshdlrdata->branchvartypeweight > 0.0 )
7093 	      {
7094 	         SCIP_VAR* var;
7095 	
7096 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7097 	         assert(var != NULL);
7098 	
7099 	         switch( SCIPvarGetType(var) )
7100 	         {
7101 	            case SCIP_VARTYPE_BINARY :
7102 	               cands[c].vartype = 1.0;
7103 	               break;
7104 	            case SCIP_VARTYPE_INTEGER :
7105 	               cands[c].vartype = 0.1;
7106 	               break;
7107 	            case SCIP_VARTYPE_IMPLINT :
7108 	               cands[c].vartype = 0.01;
7109 	               break;
7110 	            case SCIP_VARTYPE_CONTINUOUS :
7111 	            default:
7112 	               cands[c].vartype = 0.0;
7113 	         }
7114 	         maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7115 	      }
7116 	   }
7117 	
7118 	   /* now compute a weighted score for each candidate from the single scores
7119 	    * the single scores are scaled to be in [0,1] for this
7120 	    */
7121 	   for( c = 0; c < ncands; ++c )
7122 	   {
7123 	      SCIP_Real weightsum;
7124 	
7125 	      ENFOLOG(
7126 	         SCIP_VAR* var;
7127 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7128 	         SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7129 	         )
7130 	
7131 	      cands[c].weighted = 0.0;
7132 	      weightsum = 0.0;
7133 	
7134 	      if( maxscore.auxviol > 0.0 )
7135 	      {
7136 	         cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7137 	         weightsum += conshdlrdata->branchviolweight;
7138 	
7139 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7140 	      }
7141 	
7142 	      if( maxscore.domain > 0.0 )
7143 	      {
7144 	         cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7145 	         weightsum += conshdlrdata->branchdomainweight;
7146 	
7147 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7148 	      }
7149 	
7150 	      if( maxscore.dual > 0.0 )
7151 	      {
7152 	         cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7153 	         weightsum += conshdlrdata->branchdualweight;
7154 	
7155 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7156 	      }
7157 	
7158 	      if( maxscore.pscost > 0.0 )
7159 	      {
7160 	         /* use pseudo-costs only if available */
7161 	         if( cands[c].pscost != SCIP_INVALID )
7162 	         {
7163 	            cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7164 	            weightsum += conshdlrdata->branchpscostweight;
7165 	
7166 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7167 	         }
7168 	         else
7169 	         {
7170 	            /* do not add pscostscore, if not available, also do not add into weightsum */
7171 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0*    n/a(pscost)"); )
7172 	         }
7173 	      }
7174 	
7175 	      if( maxscore.vartype > 0.0 )
7176 	      {
7177 	         cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7178 	         weightsum += conshdlrdata->branchvartypeweight;
7179 	
7180 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7181 	      }
7182 	      assert(weightsum > 0.0);  /* we should have got at least one valid score */
7183 	      cands[c].weighted /= weightsum;
7184 	
7185 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7186 	   }
7187 	}
7188 	
7189 	/** compare two branching candidates by their weighted score
7190 	 *
7191 	 * if weighted score is equal, use variable index of (aux)var
7192 	 */
7193 	static
7194 	SCIP_DECL_SORTINDCOMP(branchcandCompare)
7195 	{
7196 	   BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7197 	
7198 	   if( cands[ind1].weighted != cands[ind2].weighted )
7199 	      return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7200 	   else
7201 	      return SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind1].expr)) - SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind2].expr));
7202 	}
7203 	
7204 	/** do branching or register branching candidates */
7205 	static
7206 	SCIP_RETCODE branching(
7207 	   SCIP*                 scip,               /**< SCIP data structure */
7208 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7209 	   SCIP_CONS**           conss,              /**< constraints to process */
7210 	   int                   nconss,             /**< number of constraints */
7211 	   SCIP_Real             maxrelconsviol,     /**< maximal scaled constraint violation */
7212 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
7213 	   SCIP_Longint          soltag,             /**< tag of solution */
7214 	   SCIP_RESULT*          result              /**< pointer to store the result of branching */
7215 	   )
7216 	{
7217 	   SCIP_CONSHDLRDATA* conshdlrdata;
7218 	   BRANCHCAND* cands;
7219 	   int ncands;
7220 	   SCIP_VAR* var;
7221 	   SCIP_NODE* downchild;
7222 	   SCIP_NODE* eqchild;
7223 	   SCIP_NODE* upchild;
7224 	
7225 	   assert(conshdlr != NULL);
7226 	   assert(result != NULL);
7227 	
7228 	   *result = SCIP_DIDNOTFIND;
7229 	
7230 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7231 	   assert(conshdlrdata != NULL);
7232 	
7233 	   if( conshdlrdata->branchexternal )
7234 	   {
7235 	      /* just register branching candidates as external */
7236 	      SCIP_Bool success;
7237 	
7238 	      SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7239 	      if( success )
7240 	         *result = SCIP_INFEASIBLE;
7241 	
7242 	      return SCIP_OKAY;
7243 	   }
7244 	
7245 	   /* collect branching candidates and their auxviol-score */
7246 	   SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip)) );
7247 	   SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7248 	
7249 	   /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7250 	    * we will return here and let the fallbacks in consEnfo() decide how to proceed
7251 	    */
7252 	   if( ncands == 0 )
7253 	      goto TERMINATE;
7254 	
7255 	   if( ncands > 1 )
7256 	   {
7257 	      /* if there are more than one candidate, then compute scores and select */
7258 	      int* perm;
7259 	      int c;
7260 	      int left;
7261 	      int right;
7262 	      SCIP_Real threshold;
7263 	
7264 	      /* compute additional scores on branching candidates and weighted score */
7265 	      scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7266 	
7267 	      /* sort candidates by weighted score */
7268 	      SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7269 	      SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7270 	
7271 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7272 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7273 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7274 	
7275 	      /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score)  candidate */
7276 	      left = 0;
7277 	      right = ncands - 1;
7278 	      threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7279 	      while( left < right )
7280 	      {
7281 	         int mid = (left + right) / 2;
7282 	         if( cands[perm[mid]].weighted >= threshold )
7283 	            left = mid + 1;
7284 	         else
7285 	            right = mid;
7286 	      }
7287 	      assert(left <= ncands);
7288 	
7289 	      if( left < ncands )
7290 	      {
7291 	         if( cands[perm[left]].weighted >= threshold )
7292 	         {
7293 	            assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7294 	            ncands = left + 1;
7295 	         }
7296 	         else
7297 	         {
7298 	            assert(cands[perm[left]].weighted < threshold);
7299 	            ncands = left;
7300 	         }
7301 	      }
7302 	      assert(ncands > 0);
7303 	
7304 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7305 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7306 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7307 	
7308 	      if( ncands > 1 )
7309 	      {
7310 	         /* choose at random from candidates 0..ncands-1 */
7311 	         if( conshdlrdata->branchrandnumgen == NULL )
7312 	         {
7313 	            SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7314 	         }
7315 	         c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7316 	         var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7317 	      }
7318 	      else
7319 	         var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7320 	
7321 	      SCIPfreeBufferArray(scip, &perm);
7322 	   }
7323 	   else
7324 	   {
7325 	      var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7326 	   }
7327 	   assert(var != NULL);
7328 	
7329 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7330 	            SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); )
7331 	
7332 	   SCIP_CALL( SCIPbranchVarVal(scip, var, SCIPgetBranchingPoint(scip, var, SCIP_INVALID), &downchild, &eqchild,
7333 	            &upchild) );
7334 	   if( downchild != NULL || eqchild != NULL || upchild != NULL )
7335 	      *result = SCIP_BRANCHED;
7336 	   else
7337 	      /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7338 	      *result = SCIP_REDUCEDDOM;
7339 	
7340 	 TERMINATE:
7341 	   SCIPfreeBufferArray(scip, &cands);
7342 	
7343 	   return SCIP_OKAY;
7344 	}
7345 	
7346 	/** call enforcement or estimate callback of nonlinear handler
7347 	 *
7348 	 * Calls the enforcement callback, if available.
7349 	 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7350 	 *
7351 	 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7352 	 */
7353 	static
7354 	SCIP_RETCODE enforceExprNlhdlr(
7355 	   SCIP*                 scip,               /**< SCIP main data structure */
7356 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7357 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
7358 	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
7359 	   SCIP_EXPR*            expr,               /**< expression */
7360 	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata,     /**< nonlinear handler data of expression */
7361 	   SCIP_SOL*             sol,                /**< solution to be separated (NULL for the LP solution) */
7362 	   SCIP_Real             auxvalue,           /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7363 	   SCIP_Bool             overestimate,       /**< whether the expression needs to be over- or underestimated */
7364 	   SCIP_Bool             separated,          /**< whether another nonlinear handler already added a cut for this expression */
7365 	   SCIP_Bool             allowweakcuts,      /**< whether we allow for weak cuts */
7366 	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement (and not just separation) */
7367 	   SCIP_RESULT*          result              /**< pointer to store the result */
7368 	   )
7369 	{
7370 	   assert(result != NULL);
7371 	
7372 	   /* call enforcement callback of the nlhdlr */
7373 	   SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7374 	            allowweakcuts, separated, inenforcement, result) );
7375 	
7376 	   /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7377 	   if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7378 	   {
7379 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    sepa of nlhdlr %s succeeded with result %d\n",
7380 	               SCIPnlhdlrGetName(nlhdlr), *result); )
7381 	      return SCIP_OKAY;
7382 	   }
7383 	   else
7384 	   {
7385 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    sepa of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7386 	   }
7387 	
7388 	   *result = SCIP_DIDNOTFIND;
7389 	
7390 	   /* now call the estimator callback of the nlhdlr */
7391 	   if( SCIPnlhdlrHasEstimate(nlhdlr) )
7392 	   {
7393 	      SCIP_VAR* auxvar;
7394 	      SCIP_Bool sepasuccess = FALSE;
7395 	      SCIP_Bool branchscoresuccess = FALSE;
7396 	      SCIP_PTRARRAY* rowpreps;
7397 	      int minidx;
7398 	      int maxidx;
7399 	      int r;
7400 	      SCIP_ROWPREP* rowprep;
7401 	
7402 	      SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7403 	
7404 	      auxvar = SCIPgetExprAuxVarNonlinear(expr);
7405 	      assert(auxvar != NULL);
7406 	
7407 	      SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7408 	               SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7409 	
7410 	      minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7411 	      maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7412 	
7413 	      assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7414 	
7415 	      if( !sepasuccess )
7416 	      {
7417 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s failed\n",
7418 	                  SCIPnlhdlrGetName(nlhdlr)); )
7419 	      }
7420 	
7421 	      for( r = minidx; r <= maxidx; ++r )
7422 	      {
7423 	         rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7424 	
7425 	         assert(rowprep != NULL);
7426 	         assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7427 	
7428 	         /* complete estimator to cut */
7429 	         SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7430 	
7431 	         /* add the cut and/or branching scores */
7432 	         SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7433 	               auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7434 	
7435 	         SCIPfreeRowprep(scip, &rowprep);
7436 	      }
7437 	
7438 	      SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7439 	   }
7440 	
7441 	   return SCIP_OKAY;
7442 	}
7443 	
7444 	/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7445 	 *
7446 	 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7447 	 */
7448 	static
7449 	SCIP_RETCODE enforceExpr(
7450 	   SCIP*                 scip,               /**< SCIP data structure */
7451 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
7452 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
7453 	   SCIP_EXPR*            expr,               /**< expression */
7454 	   SCIP_SOL*             sol,                /**< solution to separate, or NULL if LP solution should be used */
7455 	   SCIP_Longint          soltag,             /**< tag of solution */
7456 	   SCIP_Bool             allowweakcuts,      /**< whether we allow weak cuts */
7457 	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement (and not just separation) */
7458 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
7459 	   )
7460 	{
7461 	   SCIP_CONSHDLRDATA* conshdlrdata;
7462 	   SCIP_EXPR_OWNERDATA* ownerdata;
7463 	   SCIP_Real origviol;
7464 	   SCIP_Bool underestimate;
7465 	   SCIP_Bool overestimate;
7466 	   SCIP_Real auxviol;
7467 	   SCIP_Bool auxunderestimate;
7468 	   SCIP_Bool auxoverestimate;
7469 	   SCIP_RESULT hdlrresult;
7470 	   int e;
7471 	
7472 	   assert(scip != NULL);
7473 	   assert(expr != NULL);
7474 	   assert(result != NULL);
7475 	
7476 	   ownerdata = SCIPexprGetOwnerData(expr);
7477 	   assert(ownerdata != NULL);
7478 	   assert(ownerdata->auxvar != NULL);  /* there must be a variable attached to the expression in order to construct a cut here */
7479 	
7480 	   *result = SCIP_DIDNOTFIND;
7481 	
7482 	   /* make sure that this expression has been evaluated */
7483 	   SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7484 	
7485 	   /* decide whether under- or overestimate is required and get amount of violation */
7486 	   origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7487 	
7488 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7489 	   assert(conshdlrdata != NULL);
7490 	
7491 	   /* no sufficient violation w.r.t. the original variables -> skip expression */
7492 	   if( !overestimate && !underestimate )
7493 	   {
7494 	      return SCIP_OKAY;
7495 	   }
7496 	
7497 	   /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7498 	   for( e = 0; e < ownerdata->nenfos; ++e )
7499 	   {
7500 	      SCIP_NLHDLR* nlhdlr;
7501 	
7502 	      /* skip nlhdlr that do not want to participate in any separation */
7503 	      if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7504 	         continue;
7505 	
7506 	      nlhdlr = ownerdata->enfos[e]->nlhdlr;
7507 	      assert(nlhdlr != NULL);
7508 	
7509 	      /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7510 	      SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7511 	      ENFOLOG(
7512 	         SCIPinfoMessage(scip, enfologfile, "  expr ");
7513 	         SCIPprintExpr(scip, expr, enfologfile);
7514 	         SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7515 	            "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7516 	            SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7517 	      )
7518 	
7519 	      /* TODO if expr is root of constraint (consdata->expr == expr),
7520 	       * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7521 	       * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7522 	       * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7523 	       * so we should enforce in these auxiliaries first
7524 	       * if changing this here, we must also adapt analyzeViolation()
7525 	       */
7526 	
7527 	      auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7528 	      assert(auxviol >= 0.0);
7529 	
7530 	      /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7531 	      if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7532 	      {
7533 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7534 	                  "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7535 	                  SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7536 	
7537 	         /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7538 	         continue;
7539 	      }
7540 	
7541 	      /* 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 */
7542 	      if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7543 	      {
7544 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7545 	                  "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7546 	                  underestimate, overestimate); )
7547 	
7548 	            /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7549 	         continue;
7550 	      }
7551 	
7552 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7553 	               "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7554 	               auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7555 	
7556 	      /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7557 	       * wants to be called for separation on this side, then call separation of nlhdlr
7558 	       */
7559 	      if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7560 	      {
7561 	         /* call the separation or estimation callback of the nonlinear handler for overestimation */
7562 	         hdlrresult = SCIP_DIDNOTFIND;
7563 	         SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7564 	            ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7565 	
7566 	         if( hdlrresult == SCIP_CUTOFF )
7567 	         {
7568 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    found a cutoff -> stop separation\n"); )
7569 	            *result = SCIP_CUTOFF;
7570 	            ownerdata->lastenforced = conshdlrdata->enforound;
7571 	            break;
7572 	         }
7573 	
7574 	         if( hdlrresult == SCIP_SEPARATED )
7575 	         {
7576 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7577 	            *result = SCIP_SEPARATED;
7578 	            ownerdata->lastenforced = conshdlrdata->enforound;
7579 	            /* TODO or should we give other nlhdlr another chance? (also #3070) */
7580 	            break;
7581 	         }
7582 	
7583 	         if( hdlrresult == SCIP_REDUCEDDOM )
7584 	         {
7585 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7586 	            *result = SCIP_REDUCEDDOM;
7587 	            ownerdata->lastenforced = conshdlrdata->enforound;
7588 	            /* TODO or should we always just stop here? */
7589 	         }
7590 	
7591 	         if( hdlrresult == SCIP_BRANCHED )
7592 	         {
7593 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7594 	            assert(inenforcement);
7595 	
7596 	            /* separation and domain reduction takes precedence over branching */
7597 	            assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7598 	            if( *result == SCIP_DIDNOTFIND )
7599 	               *result = SCIP_BRANCHED;
7600 	            ownerdata->lastenforced = conshdlrdata->enforound;
7601 	         }
7602 	      }
7603 	
7604 	      /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7605 	       * wants to be called for separation on this side, then call separation of nlhdlr
7606 	       */
7607 	      if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7608 	      {
7609 	         /* call the separation or estimation callback of the nonlinear handler for underestimation */
7610 	         hdlrresult = SCIP_DIDNOTFIND;
7611 	         SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7612 	            ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7613 	
7614 	         if( hdlrresult == SCIP_CUTOFF )
7615 	         {
7616 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    found a cutoff -> stop separation\n"); )
7617 	            *result = SCIP_CUTOFF;
7618 	            ownerdata->lastenforced = conshdlrdata->enforound;
7619 	            break;
7620 	         }
7621 	
7622 	         if( hdlrresult == SCIP_SEPARATED )
7623 	         {
7624 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7625 	            *result = SCIP_SEPARATED;
7626 	            ownerdata->lastenforced = conshdlrdata->enforound;
7627 	            /* TODO or should we give other nlhdlr another chance? (also #3070) */
7628 	            break;
7629 	         }
7630 	
7631 	         if( hdlrresult == SCIP_REDUCEDDOM )
7632 	         {
7633 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7634 	            *result = SCIP_REDUCEDDOM;
7635 	            ownerdata->lastenforced = conshdlrdata->enforound;
7636 	            /* TODO or should we always just stop here? */
7637 	         }
7638 	
7639 	         if( hdlrresult == SCIP_BRANCHED )
7640 	         {
7641 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7642 	            assert(inenforcement);
7643 	
7644 	            /* separation takes precedence over branching */
7645 	            assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7646 	            if( *result == SCIP_DIDNOTFIND )
7647 	               *result = SCIP_BRANCHED;
7648 	            ownerdata->lastenforced = conshdlrdata->enforound;
7649 	         }
7650 	      }
7651 	   }
7652 	
7653 	   return SCIP_OKAY;
7654 	}
7655 	
7656 	/** helper function to enforce a single constraint */
7657 	static
7658 	SCIP_RETCODE enforceConstraint(
7659 	   SCIP*                 scip,               /**< SCIP data structure */
7660 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7661 	   SCIP_CONS*            cons,               /**< constraint to process */
7662 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
7663 	   SCIP_Longint          soltag,             /**< tag of solution */
7664 	   SCIP_EXPRITER*        it,                 /**< expression iterator that we can just use here */
7665 	   SCIP_Bool             allowweakcuts,      /**< whether to allow weak cuts in this round */
7666 	   SCIP_Bool             inenforcement,      /**< whether to we are in enforcement, and not just separation */
7667 	   SCIP_RESULT*          result,             /**< pointer to update with result of the enforcing call */
7668 	   SCIP_Bool*            success             /**< buffer to store whether some enforcement took place */
7669 	   )
7670 	{
7671 	   SCIP_CONSDATA* consdata;
7672 	   SCIP_CONSHDLRDATA* conshdlrdata;
7673 	   SCIP_EXPR* expr;
7674 	
7675 	   assert(conshdlr != NULL);
7676 	   assert(cons != NULL);
7677 	   assert(it != NULL);
7678 	   assert(result != NULL);
7679 	   assert(success != NULL);
7680 	
7681 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7682 	   assert(conshdlrdata != NULL);
7683 	
7684 	   consdata = SCIPconsGetData(cons);
7685 	   assert(consdata != NULL);
7686 	   assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7687 	
7688 	   *success = FALSE;
7689 	
7690 	   if( inenforcement && !consdata->ispropagated )
7691 	   {
7692 	      /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7693 	       * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7694 	       * (TODO: nlhdlr tells us now whether they do and so we could skip).
7695 	       * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7696 	       * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7697 	       * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7698 	       * confuse the stalling check for how long to do separation).
7699 	       */
7700 	      SCIP_Bool infeasible;
7701 	      int ntightenings;
7702 	
7703 	      SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7704 	      if( infeasible )
7705 	      {
7706 	         *result = SCIP_CUTOFF;
7707 	         return SCIP_OKAY;
7708 	      }
7709 	      /* if we tightened an auxvar bound, we better communicate that */
7710 	      if( ntightenings > 0 )
7711 	         *result = SCIP_REDUCEDDOM;
7712 	   }
7713 	
7714 	   for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7715 	   {
7716 	      SCIP_EXPR_OWNERDATA* ownerdata;
7717 	      SCIP_RESULT resultexpr;
7718 	
7719 	      ownerdata = SCIPexprGetOwnerData(expr);
7720 	      assert(ownerdata != NULL);
7721 	
7722 	      /* we can only enforce if there is an auxvar to compare with */
7723 	      if( ownerdata->auxvar == NULL )
7724 	         continue;
7725 	
7726 	      assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7727 	      if( ownerdata->lastenforced == conshdlrdata->enforound )
7728 	      {
7729 	         ENFOLOG(
7730 	            SCIPinfoMessage(scip, enfologfile, "  skip expr ");
7731 	            SCIPprintExpr(scip, expr, enfologfile);
7732 	            SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7733 	         )
7734 	         *success = TRUE;
7735 	         continue;
7736 	      }
7737 	
7738 	      SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7739 	
7740 	      /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7741 	      assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7742 	      if( ownerdata->lastenforced == conshdlrdata->enforound )
7743 	         *success = TRUE;
7744 	
7745 	      if( resultexpr == SCIP_CUTOFF )
7746 	      {
7747 	         *result = SCIP_CUTOFF;
7748 	         break;
7749 	      }
7750 	
7751 	      if( resultexpr == SCIP_SEPARATED )
7752 	         *result = SCIP_SEPARATED;
7753 	
7754 	      if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7755 	         *result = SCIP_REDUCEDDOM;
7756 	
7757 	      if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7758 	         *result = SCIP_BRANCHED;
7759 	   }
7760 	
7761 	   return SCIP_OKAY;
7762 	}
7763 	
7764 	/** try to separate violated constraints and, if in enforcement, register branching scores
7765 	 *
7766 	 * Sets result to
7767 	 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7768 	 * - SCIP_CUTOFF, if node can be cutoff,
7769 	 * - SCIP_SEPARATED, if a cut has been added,
7770 	 * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7771 	 * - SCIP_BRANCHED, if branching has been done,
7772 	 * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7773 	 * - SCIP_INFEASIBLE, if external branching candidates were registered
7774 	 */
7775 	static
7776 	SCIP_RETCODE enforceConstraints(
7777 	   SCIP*                 scip,               /**< SCIP data structure */
7778 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7779 	   SCIP_CONS**           conss,              /**< constraints to process */
7780 	   int                   nconss,             /**< number of constraints */
7781 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
7782 	   SCIP_Longint          soltag,             /**< tag of solution */
7783 	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement, and not just separation */
7784 	   SCIP_Real             maxrelconsviol,     /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7785 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
7786 	   )
7787 	{
7788 	   SCIP_CONSHDLRDATA* conshdlrdata;
7789 	   SCIP_EXPRITER* it;
7790 	   SCIP_Bool consenforced;  /* whether any expression in constraint could be enforced */
7791 	   int c;
7792 	
7793 	   assert(conshdlr != NULL);
7794 	   assert(conss != NULL || nconss == 0);
7795 	   assert(result != NULL);
7796 	
7797 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7798 	   assert(conshdlrdata != NULL);
7799 	
7800 	   /* increase tag to tell whether branching scores in expression belong to this sweep
7801 	    * and which expressions have already been enforced in this sweep
7802 	    * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7803 	    */
7804 	   ++(conshdlrdata->enforound);
7805 	
7806 	   *result = SCIP_DIDNOTFIND;
7807 	
7808 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7809 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, TRUE) );
7810 	
7811 	   for( c = 0; c < nconss; ++c )
7812 	   {
7813 	      assert(conss != NULL && conss[c] != NULL);
7814 	
7815 	      /* skip constraints that are not enabled or deleted */
7816 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7817 	         continue;
7818 	      assert(SCIPconsIsActive(conss[c]));
7819 	
7820 	      /* skip constraints that have separation disabled if we are only in separation */
7821 	      if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7822 	         continue;
7823 	
7824 	      /* skip non-violated constraints */
7825 	      if( !isConsViolated(scip, conss[c]) )
7826 	         continue;
7827 	
7828 	      ENFOLOG(
7829 	      {
7830 	         SCIP_CONSDATA* consdata;
7831 	         int i;
7832 	         consdata = SCIPconsGetData(conss[c]);
7833 	         assert(consdata != NULL);
7834 	         SCIPinfoMessage(scip, enfologfile, " constraint ");
7835 	         SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7836 	         SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7837 	         for( i = 0; i < consdata->nvarexprs; ++i )
7838 	         {
7839 	            SCIP_VAR* var;
7840 	            var = SCIPgetVarExprVar(consdata->varexprs[i]);
7841 	            SCIPinfoMessage(scip, enfologfile, "  %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7842 	                  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7843 	         }
7844 	      })
7845 	
7846 	      SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, result, &consenforced) );
7847 	
7848 	      if( *result == SCIP_CUTOFF )
7849 	         break;
7850 	
7851 	      if( !consenforced && inenforcement )
7852 	      {
7853 	         SCIP_Real viol;
7854 	
7855 	         SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7856 	         if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7857 	         {
7858 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7859 	                     "cuts allowed\n", SCIPconsGetName(conss[c])); )
7860 	
7861 	            SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, result, &consenforced) );
7862 	
7863 	            if( consenforced )
7864 	               ++conshdlrdata->nweaksepa;  /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7865 	
7866 	            if( *result == SCIP_CUTOFF )
7867 	               break;
7868 	         }
7869 	      }
7870 	   }
7871 	
7872 	   SCIPfreeExpriter(&it);
7873 	
7874 	   ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7875 	
7876 	   /* if having branching scores, then propagate them from expressions with children to variable expressions */
7877 	   if( *result == SCIP_BRANCHED )
7878 	   {
7879 	      /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7880 	       * branching
7881 	       */
7882 	      SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7883 	
7884 	      /* branching should either have branched: result == SCIP_BRANCHED,
7885 	       * or fixed a variable: result == SCIP_REDUCEDDOM,
7886 	       * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7887 	       * or have not done anything: result == SCIP_DIDNOTFIND
7888 	       */
7889 	      assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7890 	   }
7891 	
7892 	   ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7893 	
7894 	   return SCIP_OKAY;
7895 	}
7896 	
7897 	/** collect (and print (if debugging enfo)) information on violation in expressions
7898 	 *
7899 	 * assumes that constraint violations have been computed
7900 	 */
7901 	static
7902 	SCIP_RETCODE analyzeViolation(
7903 	   SCIP*                 scip,               /**< SCIP data structure */
7904 	   SCIP_CONS**           conss,              /**< constraints */
7905 	   int                   nconss,             /**< number of constraints */
7906 	   SCIP_SOL*             sol,                /**< solution to separate, or NULL if LP solution should be used */
7907 	   SCIP_Longint          soltag,             /**< tag of solution */
7908 	   SCIP_Real*            maxabsconsviol,     /**< buffer to store maximal absolute violation of constraints */
7909 	   SCIP_Real*            maxrelconsviol,     /**< buffer to store maximal relative violation of constraints */
7910 	   SCIP_Real*            minauxviol,         /**< buffer to store minimal (nonzero) violation of auxiliaries */
7911 	   SCIP_Real*            maxauxviol,         /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7912 	   SCIP_Real*            maxvarboundviol     /**< buffer to store maximal violation of variable bounds */
7913 	   )
7914 	{
7915 	   SCIP_CONSDATA* consdata;
7916 	   SCIP_EXPRITER* it;
7917 	   SCIP_EXPR* expr;
7918 	   SCIP_Real v;
7919 	   int c;
7920 	
7921 	   assert(conss != NULL || nconss == 0);
7922 	   assert(maxabsconsviol != NULL);
7923 	   assert(maxrelconsviol != NULL);
7924 	   assert(maxauxviol != NULL);
7925 	   assert(maxvarboundviol != NULL);
7926 	
7927 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7928 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
7929 	
7930 	   *maxabsconsviol = 0.0;
7931 	   *maxrelconsviol = 0.0;
7932 	   *minauxviol = SCIPinfinity(scip);
7933 	   *maxauxviol = 0.0;
7934 	   *maxvarboundviol = 0.0;
7935 	
7936 	   for( c = 0; c < nconss; ++c )
7937 	   {
7938 	      assert(conss != NULL && conss[c] != NULL);
7939 	
7940 	      consdata = SCIPconsGetData(conss[c]);
7941 	      assert(consdata != NULL);
7942 	
7943 	      /* skip constraints that are not enabled, deleted, or have separation disabled */
7944 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7945 	         continue;
7946 	      assert(SCIPconsIsActive(conss[c]));
7947 	
7948 	      v = getConsAbsViolation(conss[c]);
7949 	      *maxabsconsviol = MAX(*maxabsconsviol, v);
7950 	
7951 	      /* skip non-violated constraints */
7952 	      if( !isConsViolated(scip, conss[c]) )
7953 	         continue;
7954 	
7955 	      SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
7956 	      *maxrelconsviol = MAX(*maxrelconsviol, v);
7957 	
7958 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7959 	      {
7960 	         SCIP_EXPR_OWNERDATA* ownerdata;
7961 	         SCIP_Real auxvarvalue;
7962 	         SCIP_Real auxvarlb;
7963 	         SCIP_Real auxvarub;
7964 	         SCIP_Bool violunder;
7965 	         SCIP_Bool violover;
7966 	         SCIP_Real origviol;
7967 	         SCIP_Real auxviol;
7968 	         int e;
7969 	
7970 	         ownerdata = SCIPexprGetOwnerData(expr);
7971 	         assert(ownerdata != NULL);
7972 	
7973 	         if( ownerdata->auxvar == NULL )
7974 	         {
7975 	            /* check violation of variable bounds of original variable */
7976 	            if( SCIPisExprVar(scip, expr) )
7977 	            {
7978 	               SCIP_VAR* var;
7979 	               var = SCIPgetVarExprVar(expr);
7980 	               auxvarvalue = SCIPgetSolVal(scip, sol, var);
7981 	               auxvarlb = SCIPvarGetLbLocal(var);
7982 	               auxvarub = SCIPvarGetUbLocal(var);
7983 	
7984 	               origviol = 0.0;
7985 	               if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
7986 	                  origviol = auxvarlb - auxvarvalue;
7987 	               else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
7988 	                  origviol = auxvarvalue - auxvarub;
7989 	               if( origviol <= 0.0 )
7990 	                  continue;
7991 	
7992 	               *maxvarboundviol = MAX(*maxvarboundviol, origviol);
7993 	
7994 	               ENFOLOG(
7995 	               SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
7996 	               if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
7997 	                  SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
7998 	               if( auxvarub < auxvarvalue && !SCIPisInfinity(scip,  auxvarub) )
7999 	                  SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8000 	               SCIPinfoMessage(scip, enfologfile, "\n");
8001 	               )
8002 	            }
8003 	
8004 	            continue;
8005 	         }
8006 	
8007 	         auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8008 	         auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8009 	         auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8010 	
8011 	         /* check violation of variable bounds of auxiliary variable */
8012 	         if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8013 	            *maxvarboundviol = auxvarlb - auxvarvalue;
8014 	         else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip,  auxvarub) )
8015 	            *maxvarboundviol = auxvarvalue - auxvarub;
8016 	
8017 	         origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8018 	
8019 	         ENFOLOG(
8020 	         if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8021 	         {
8022 	            SCIPinfoMessage(scip, enfologfile, "expr ");
8023 	            SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8024 	            SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8025 	
8026 	            SCIPinfoMessage(scip, enfologfile, "  auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8027 	            if( origviol > 0.0 )
8028 	               SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8029 	            if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8030 	               SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8031 	            if( auxvarub < auxvarvalue && !SCIPisInfinity(scip,  auxvarub) )
8032 	               SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8033 	            SCIPinfoMessage(scip, enfologfile, "\n");
8034 	         }
8035 	         )
8036 	
8037 	         /* no violation w.r.t. the original variables -> skip expression */
8038 	         if( origviol == 0.0 )
8039 	            continue;
8040 	
8041 	         /* compute aux-violation for each nonlinear handlers */
8042 	         for( e = 0; e < ownerdata->nenfos; ++e )
8043 	         {
8044 	            SCIP_NLHDLR* nlhdlr;
8045 	
8046 	            /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8047 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8048 	               continue;
8049 	
8050 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
8051 	            assert(nlhdlr != NULL);
8052 	
8053 	            /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8054 	            SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8055 	
8056 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "  nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8057 	
8058 	            auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8059 	
8060 	            if( auxviol > 0.0 )
8061 	            {
8062 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8063 	               *maxauxviol = MAX(*maxauxviol, auxviol);
8064 	               *minauxviol = MIN(*minauxviol, auxviol);
8065 	            }
8066 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8067 	         }
8068 	      }
8069 	   }
8070 	
8071 	   SCIPfreeExpriter(&it);
8072 	
8073 	   return SCIP_OKAY;
8074 	} /*lint !e715*/
8075 	
8076 	/** enforcement of constraints called by enfolp and enforelax */
8077 	static
8078 	SCIP_RETCODE consEnfo(
8079 	   SCIP*                 scip,               /**< SCIP data structure */
8080 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
8081 	   SCIP_CONS**           conss,              /**< constraints to process */
8082 	   int                   nconss,             /**< number of constraints */
8083 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
8084 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
8085 	   )
8086 	{
8087 	   SCIP_CONSHDLRDATA* conshdlrdata;
8088 	   SCIP_Real maxabsconsviol;
8089 	   SCIP_Real maxrelconsviol;
8090 	   SCIP_Real minauxviol;
8091 	   SCIP_Real maxauxviol;
8092 	   SCIP_Real maxvarboundviol;
8093 	   SCIP_Longint soltag;
8094 	   int nnotify;
8095 	   int c;
8096 	
8097 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8098 	   assert(conshdlr != NULL);
8099 	
8100 	   soltag = SCIPgetExprNewSoltag(scip);
8101 	
8102 	   *result = SCIP_FEASIBLE;
8103 	   for( c = 0; c < nconss; ++c )
8104 	   {
8105 	      SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8106 	
8107 	      if( isConsViolated(scip, conss[c]) )
8108 	         *result = SCIP_INFEASIBLE;
8109 	   }
8110 	
8111 	   if( *result == SCIP_FEASIBLE )
8112 	   {
8113 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8114 	               SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8115 	      return SCIP_OKAY;
8116 	   }
8117 	
8118 	   SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8119 	            &minauxviol, &maxauxviol, &maxvarboundviol) );
8120 	
8121 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8122 	            "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8123 	            SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8124 	            maxvarboundviol, SCIPgetLPFeastol(scip)); )
8125 	
8126 	   assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8127 	
8128 	   /* try to propagate */
8129 	   if( conshdlrdata->propinenforce )
8130 	   {
8131 	      SCIP_RESULT propresult;
8132 	      int nchgbds = 0;
8133 	
8134 	      SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8135 	
8136 	      if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8137 	      {
8138 	         *result = propresult;
8139 	         return SCIP_OKAY;
8140 	      }
8141 	   }
8142 	
8143 	   /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8144 	    * all violated expr/auxvar in violated constraints)
8145 	    */
8146 	   if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8147 	         sol == NULL )
8148 	   {
8149 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8150 	      ++conshdlrdata->ntightenlp;
8151 	
8152 	      *result = SCIP_SOLVELP;
8153 	
8154 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8155 	               "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8156 	
8157 	      return SCIP_OKAY;
8158 	   }
8159 	
8160 	   /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8161 	    * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8162 	    */
8163 	   if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8164 	   {
8165 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8166 	      ++conshdlrdata->ntightenlp;
8167 	
8168 	      *result = SCIP_SOLVELP;
8169 	
8170 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8171 	
8172 	      return SCIP_OKAY;
8173 	   }
8174 	
8175 	   SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8176 	
8177 	   if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8178 	         *result == SCIP_INFEASIBLE )
8179 	      return SCIP_OKAY;
8180 	
8181 	   assert(*result == SCIP_DIDNOTFIND);
8182 	
8183 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8184 	            "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8185 	
8186 	   if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8187 	   {
8188 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8189 	      ++conshdlrdata->ntightenlp;
8190 	
8191 	      *result = SCIP_SOLVELP;
8192 	
8193 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8194 	               "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8195 	
8196 	      return SCIP_OKAY;
8197 	   }
8198 	
8199 	   if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8200 	            SCIPgetLPFeastol(scip)) && sol == NULL )
8201 	   {
8202 	      /* try whether tighten the LP feasibility tolerance could help
8203 	       * maybe it is just some cut that hasn't been taken into account sufficiently
8204 	       * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8205 	       * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8206 	       * until the LP feastol reaches epsilon
8207 	       * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8208 	       * when maxauxviol is above LP feastol)
8209 	       */
8210 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8211 	      ++conshdlrdata->ndesperatetightenlp;
8212 	
8213 	      *result = SCIP_SOLVELP;
8214 	
8215 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8216 	
8217 	      return SCIP_OKAY;
8218 	   }
8219 	
8220 	   /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8221 	   if( !conshdlrdata->propinenforce )
8222 	   {
8223 	      SCIP_RESULT propresult;
8224 	      int nchgbds = 0;
8225 	
8226 	      SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8227 	
8228 	      if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8229 	      {
8230 	         *result = propresult;
8231 	         return SCIP_OKAY;
8232 	      }
8233 	   }
8234 	
8235 	   /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8236 	    * now look if we find any unfixed variable that we could still branch on
8237 	    */
8238 	   SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8239 	
8240 	   if( nnotify > 0 )
8241 	   {
8242 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8243 	      ++conshdlrdata->ndesperatebranch;
8244 	
8245 	      *result = SCIP_INFEASIBLE;  /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8246 	
8247 	      return SCIP_OKAY;
8248 	   }
8249 	
8250 	   /* if everything is fixed in violated constraints, then let's cut off the node
8251 	    * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8252 	    *   result may not be conclusive (when constraint violations are small)
8253 	    * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8254 	    *   sufficiently (see st_e40)
8255 	    * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8256 	    *   not "desperate", but a pretty obvious thing to do
8257 	    */
8258 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8259 	   *result = SCIP_CUTOFF;
8260 	
8261 	   /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8262 	   if( !SCIPisZero(scip, maxvarboundviol) )
8263 	      ++conshdlrdata->ndesperatecutoff;
8264 	
8265 	   return SCIP_OKAY;
8266 	}
8267 	
8268 	/** separation for all violated constraints to be used by SEPA callbacks */
8269 	static
8270 	SCIP_RETCODE consSepa(
8271 	   SCIP*                 scip,               /**< SCIP data structure */
8272 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
8273 	   SCIP_CONS**           conss,              /**< constraints to process */
8274 	   int                   nconss,             /**< number of constraints */
8275 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
8276 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
8277 	   )
8278 	{
8279 	   SCIP_Longint soltag;
8280 	   SCIP_Bool haveviol = FALSE;
8281 	   int c;
8282 	
8283 	   *result = SCIP_DIDNOTFIND;
8284 	
8285 	   soltag = SCIPgetExprNewSoltag(scip);
8286 	
8287 	   /* compute violations */
8288 	   for( c = 0; c < nconss; ++c )
8289 	   {
8290 	      assert(conss[c] != NULL);
8291 	
8292 	      /* skip constraints that are not enabled, deleted, or have separation disabled */
8293 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8294 	         continue;
8295 	      assert(SCIPconsIsActive(conss[c]));
8296 	
8297 	      SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8298 	
8299 	      if( isConsViolated(scip, conss[c]) )
8300 	         haveviol = TRUE;
8301 	   }
8302 	
8303 	   /* if none of our constraints are violated, don't attempt separation */
8304 	   if( !haveviol )
8305 	   {
8306 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8307 	      return SCIP_OKAY;
8308 	   }
8309 	
8310 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8311 	
8312 	   /* call separation */
8313 	   SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8314 	
8315 	   return SCIP_OKAY;
8316 	}
8317 	
8318 	/** hash key retrieval function for bilinear term entries */
8319 	static
8320 	SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8321 	{  /*lint --e{715}*/
8322 	   SCIP_CONSHDLRDATA* conshdlrdata;
8323 	   int idx;
8324 	
8325 	   conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8326 	   assert(conshdlrdata != NULL);
8327 	
8328 	   idx = ((int)(size_t)elem) - 1;
8329 	   assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8330 	
8331 	   return (void*)&conshdlrdata->bilinterms[idx];
8332 	}
8333 	
8334 	/** returns TRUE iff the bilinear term entries are equal */
8335 	static
8336 	SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8337 	{  /*lint --e{715}*/
8338 	   SCIP_CONSNONLINEAR_BILINTERM* entry1;
8339 	   SCIP_CONSNONLINEAR_BILINTERM* entry2;
8340 	
8341 	   /* get corresponding entries */
8342 	   entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8343 	   entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8344 	   assert(entry1->x != NULL && entry1->y != NULL);
8345 	   assert(entry2->x != NULL && entry2->y != NULL);
8346 	   assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8347 	   assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8348 	
8349 	   return entry1->x == entry2->x && entry1->y == entry2->y;
8350 	}
8351 	
8352 	/** returns the hash value of the key */
8353 	static
8354 	SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8355 	{  /*lint --e{715}*/
8356 	   SCIP_CONSNONLINEAR_BILINTERM* entry;
8357 	
8358 	   entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8359 	   assert(entry->x != NULL && entry->y != NULL);
8360 	   assert(SCIPvarCompare(entry->x, entry->y) < 1);
8361 	
8362 	   return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8363 	}
8364 	
8365 	/** compare two auxiliary expressions
8366 	 *
8367 	 *  Compares auxiliary variables, followed by coefficients, and then constants.
8368 	 */
8369 	static
8370 	SCIP_DECL_SORTPTRCOMP(auxexprComp)
8371 	{
8372 	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr1 = (SCIP_CONSNONLINEAR_AUXEXPR*)elem1;
8373 	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr2 = (SCIP_CONSNONLINEAR_AUXEXPR*)elem2;
8374 	   int compvars;
8375 	   int i;
8376 	
8377 	   /* compare the auxiliary variables */
8378 	   compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8379 	
8380 	   if( compvars != 0 )
8381 	      return compvars;
8382 	
8383 	   /* compare the coefficients and constants */
8384 	   for( i = 0; i < 3; ++i )
8385 	   {
8386 	      if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8387 	         return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8388 	   }
8389 	
8390 	   return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8391 	}
8392 	
8393 	/* add an auxiliary expression to a bilinear term */
8394 	static
8395 	SCIP_RETCODE bilinTermAddAuxExpr(
8396 	   SCIP*                 scip,               /**< SCIP data structure */
8397 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< nonlinear constraint handler data */
8398 	   SCIP_CONSNONLINEAR_BILINTERM* term,       /**< bilinear term */
8399 	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr,      /**< auxiliary expression to add */
8400 	   SCIP_Bool*            added               /**< pointer to store whether auxexpr has been added */
8401 	   )
8402 	{
8403 	   SCIP_Bool found;
8404 	   int pos;
8405 	   int i;
8406 	
8407 	   *added = FALSE;
8408 	
8409 	   /* check if auxexpr has already been added to term */
8410 	   if( term->nauxexprs == 0 )
8411 	   {
8412 	      found = FALSE;
8413 	      pos = 0;
8414 	   }
8415 	   else
8416 	   {
8417 	      found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8418 	   }
8419 	
8420 	   if( !found )
8421 	   {
8422 	      if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8423 	         return SCIP_OKAY;
8424 	
8425 	      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8426 	      assert(term->auxexprssize >= term->nauxexprs + 1);
8427 	
8428 	      /* insert expression at the correct position */
8429 	      for( i = term->nauxexprs; i > pos; --i )
8430 	      {
8431 	         term->aux.exprs[i] = term->aux.exprs[i-1];
8432 	      }
8433 	      term->aux.exprs[pos] = auxexpr;
8434 	      ++(term->nauxexprs);
8435 	      *added = TRUE;
8436 	   }
8437 	   else
8438 	   {
8439 	      term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8440 	      term->aux.exprs[pos]->overestimate  |= auxexpr->overestimate;
8441 	   }
8442 	
8443 	   return SCIP_OKAY;
8444 	}
8445 	
8446 	/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8447 	static
8448 	SCIP_RETCODE bilinearTermsInsertAll(
8449 	   SCIP*                 scip,               /**< SCIP data structure */
8450 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
8451 	   SCIP_CONS**           conss,              /**< nonlinear constraints */
8452 	   int                   nconss              /**< total number of nonlinear constraints */
8453 	   )
8454 	{
8455 	   SCIP_CONSHDLRDATA* conshdlrdata;
8456 	   SCIP_EXPRITER* it;
8457 	   int c;
8458 	
8459 	   assert(conss != NULL || nconss == 0);
8460 	
8461 	   if( nconss == 0 )
8462 	      return SCIP_OKAY;
8463 	
8464 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8465 	   assert(conshdlrdata != NULL);
8466 	
8467 	   /* check whether the bilinear terms have been stored already */
8468 	   if( conshdlrdata->bilinterms != NULL )
8469 	      return SCIP_OKAY;
8470 	
8471 	   /* create and initialize iterator */
8472 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8473 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
8474 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR);
8475 	
8476 	   /* iterate through all constraints */
8477 	   for( c = 0; c < nconss; ++c )
8478 	   {
8479 	      SCIP_CONSDATA* consdata;
8480 	      SCIP_EXPR* expr;
8481 	
8482 	      assert(conss != NULL && conss[c] != NULL);
8483 	      consdata = SCIPconsGetData(conss[c]);
8484 	      assert(consdata != NULL);
8485 	
8486 	      /* iterate through all expressions */
8487 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8488 	      {
8489 	         SCIP_EXPR** children = SCIPexprGetChildren(expr);
8490 	         SCIP_VAR* x = NULL;
8491 	         SCIP_VAR* y = NULL;
8492 	
8493 	         /* check whether the expression is of the form f(..)^2 */
8494 	         if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8495 	         {
8496 	            x = SCIPgetExprAuxVarNonlinear(children[0]);
8497 	            y = x;
8498 	         }
8499 	         /* check whether the expression is of the form f(..) * g(..) */
8500 	         else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8501 	         {
8502 	            x = SCIPgetExprAuxVarNonlinear(children[0]);
8503 	            y = SCIPgetExprAuxVarNonlinear(children[1]);
8504 	         }
8505 	
8506 	         /* add variables to the hash table */
8507 	         if( x != NULL && y != NULL )
8508 	         {
8509 	            SCIP_CALL( SCIPinsertBilinearTermExistingNonlinear(scip, conshdlr, x, y, SCIPgetExprAuxVarNonlinear(expr),
8510 	               SCIPgetExprNLocksPosNonlinear(expr), SCIPgetExprNLocksNegNonlinear(expr)) );
8511 	         }
8512 	      }
8513 	   }
8514 	
8515 	   /* release iterator */
8516 	   SCIPfreeExpriter(&it);
8517 	
8518 	   return SCIP_OKAY;
8519 	}
8520 	
8521 	/** store x, y and the locks in a new bilinear term */
8522 	static
8523 	SCIP_RETCODE bilinearTermsInsertEntry(
8524 	   SCIP*                 scip,               /**< SCIP data structure */
8525 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
8526 	   SCIP_VAR*             x,                  /**< the first variable */
8527 	   SCIP_VAR*             y,                  /**< the second variable */
8528 	   int                   nlockspos,          /**< number of positive locks of the bilinear term */
8529 	   int                   nlocksneg,          /**< number of negative locks of the bilinear term */
8530 	   int*                  idx,                /**< pointer to store the position of the term in bilinterms array */
8531 	   SCIP_Bool             existing            /**< whether the term exists explicitly in the problem */
8532 	   )
8533 	{
8534 	   SCIP_CONSHDLRDATA* conshdlrdata;
8535 	   SCIP_CONSNONLINEAR_BILINTERM* term;
8536 	
8537 	   assert(conshdlr != NULL);
8538 	   assert(x != NULL);
8539 	   assert(y != NULL);
8540 	   assert(nlockspos >= 0);
8541 	   assert(nlocksneg >= 0);
8542 	
8543 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8544 	   assert(conshdlrdata != NULL);
8545 	
8546 	   /* ensure that x.index <= y.index */
8547 	   if( SCIPvarCompare(x, y) == 1 )
8548 	   {
8549 	      SCIPswapPointers((void**)&x, (void**)&y);
8550 	   }
8551 	   assert(SCIPvarCompare(x, y) < 1);
8552 	
8553 	   *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8554 	
8555 	   /* update or create the term */
8556 	   if( *idx >= 0 )
8557 	   { /* the term has already been added */
8558 	      assert(conshdlrdata->bilinterms[*idx].x == x);
8559 	      assert(conshdlrdata->bilinterms[*idx].y == y);
8560 	
8561 	      /* get term and add locks */
8562 	      term = &conshdlrdata->bilinterms[*idx];
8563 	      assert(existing <= term->existing); /* implicit terms are added after existing ones */
8564 	      term->nlockspos += nlockspos;
8565 	      term->nlocksneg += nlocksneg;
8566 	   }
8567 	   else
8568 	   { /* this is the first time we encounter this product */
8569 	      /* ensure size of bilinterms array */
8570 	      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8571 	
8572 	      *idx = conshdlrdata->nbilinterms;
8573 	
8574 	      /* get term and set values in the created bilinear term */
8575 	      term = &conshdlrdata->bilinterms[*idx];
8576 	      assert(term != NULL);
8577 	      term->x = x;
8578 	      term->y = y;
8579 	      term->nauxexprs = 0;
8580 	      term->auxexprssize = 0;
8581 	      term->nlockspos = nlockspos;
8582 	      term->nlocksneg = nlocksneg;
8583 	      term->existing = existing;
8584 	      if( existing )
8585 	         term->aux.var = NULL;
8586 	      else
8587 	         term->aux.exprs = NULL;
8588 	
8589 	      /* increase the total number of bilinear terms */
8590 	      ++(conshdlrdata->nbilinterms);
8591 	
8592 	      /* save to the hashtable */
8593 	      if( conshdlrdata->bilinhashtable == NULL )
8594 	      {
8595 	         SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8596 	               bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8597 	               (void*)conshdlrdata) );
8598 	      }
8599 	      assert(conshdlrdata->bilinhashtable != NULL);
8600 	
8601 	      /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8602 	       * because zero can not be inserted into hash table
8603 	       */
8604 	      SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8605 	
8606 	      /* capture product variables */
8607 	      SCIP_CALL( SCIPcaptureVar(scip, x) );
8608 	      SCIP_CALL( SCIPcaptureVar(scip, y) );
8609 	   }
8610 	
8611 	   return SCIP_OKAY;
8612 	}
8613 	
8614 	/** frees array of bilinear terms and hash table */
8615 	static
8616 	SCIP_RETCODE bilinearTermsFree(
8617 	   SCIP*                 scip,               /**< SCIP data structure */
8618 	   SCIP_CONSHDLRDATA*    conshdlrdata        /**< constraint handler data */
8619 	   )
8620 	{
8621 	   int i;
8622 	   int j;
8623 	
8624 	   assert(conshdlrdata != NULL);
8625 	
8626 	   /* check whether bilinear terms have been stored */
8627 	   if( conshdlrdata->bilinterms == NULL )
8628 	   {
8629 	      assert(conshdlrdata->bilinterms == NULL);
8630 	      assert(conshdlrdata->nbilinterms == 0);
8631 	      assert(conshdlrdata->bilintermssize == 0);
8632 	
8633 	      return SCIP_OKAY;
8634 	   }
8635 	
8636 	   /* release variables */
8637 	   for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8638 	   {
8639 	      SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8640 	      SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8641 	
8642 	      for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8643 	      {
8644 	         if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8645 	         {
8646 	            SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8647 	         }
8648 	         SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8649 	      }
8650 	
8651 	      if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8652 	      {
8653 	         SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8654 	         continue;
8655 	      }
8656 	
8657 	      /* the rest is for simple terms with a single auxvar */
8658 	
8659 	      /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8660 	      if( conshdlrdata->bilinterms[i].aux.var != NULL )
8661 	      {
8662 	         SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8663 	      }
8664 	   }
8665 	
8666 	   /* free hash table */
8667 	   if( conshdlrdata->bilinhashtable != NULL )
8668 	   {
8669 	      SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8670 	   }
8671 	
8672 	   /* free bilinterms array; reset counters */
8673 	   SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8674 	   conshdlrdata->nbilinterms = 0;
8675 	   conshdlrdata->bilintermssize = 0;
8676 	
8677 	   return SCIP_OKAY;
8678 	}
8679 	
8680 	/*
8681 	 * vertex polyhedral separation
8682 	 */
8683 	
8684 	/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8685 	static
8686 	SCIP_RETCODE buildVertexPolyhedralSeparationLP(
8687 	   SCIP*                 scip,               /**< SCIP data structure */
8688 	   int                   nvars,              /**< number of (unfixed) variables in vertex-polyhedral functions */
8689 	   SCIP_LPI**            lp                  /**< pointer to store created LP */
8690 	   )
8691 	{
8692 	   SCIP_Real* obj;
8693 	   SCIP_Real* lb;
8694 	   SCIP_Real* ub;
8695 	   SCIP_Real* val;
8696 	   int* beg;
8697 	   int* ind;
8698 	   unsigned int nnonz;
8699 	   unsigned int ncols;
8700 	   unsigned int nrows;
8701 	   unsigned int i;
8702 	   unsigned int k;
8703 	
8704 	   assert(scip != NULL);
8705 	   assert(lp != NULL);
8706 	   assert(nvars > 0);
8707 	   assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8708 	
8709 	   SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8710 	
8711 	   /* create lpi to store the LP */
8712 	   SCIP_CALL( SCIPlpiCreate(lp, SCIPgetMessagehdlr(scip), "facet finding LP", SCIP_OBJSEN_MINIMIZE) );
8713 	
8714 	   nrows = (unsigned int)nvars + 1;
8715 	   ncols = POWEROFTWO((unsigned int)nvars);
8716 	   nnonz = (ncols * (nrows + 1)) / 2;
8717 	
8718 	   /* allocate necessary memory; set obj, lb, and ub to zero */
8719 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
8720 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &lb, ncols) );
8721 	   SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8722 	   SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8723 	   SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8724 	   SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8725 	
8726 	   /* calculate nonzero entries in the LP */
8727 	   for( i = 0, k = 0; i < ncols; ++i )
8728 	   {
8729 	      int row;
8730 	      unsigned int a;
8731 	
8732 	      /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8733 	      ub[i] = SCIPlpiInfinity(*lp);
8734 	
8735 	      SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8736 	      beg[i] = (int)k;
8737 	      row = 0;
8738 	
8739 	      /* iterate through the bit representation of i */
8740 	      a = 1;
8741 	      while( a <= i )
8742 	      {
8743 	         if( (a & i) != 0 )
8744 	         {
8745 	            val[k] = 1.0;
8746 	            ind[k] = row;
8747 	
8748 	            SCIPdebugMsg(scip, " val[%d][%u] = 1 (position  %u)\n", row, i, k);
8749 	
8750 	            ++k;
8751 	         }
8752 	
8753 	         a <<= 1;
8754 	         ++row;
8755 	         assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8756 	         assert(POWEROFTWO(row) == a);
8757 	      }
8758 	
8759 	      /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8760 	      val[k] = 1.0;
8761 	      ind[k] = (int)nrows - 1;
8762 	      ++k;
8763 	      SCIPdebugMsg(scip, " val[%u][%u] = 1 (position  %u)\n", nrows - 1, i, k);
8764 	   }
8765 	   assert(k == nnonz);
8766 	
8767 	   /* load all data into LP interface
8768 	    * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8769 	    */
8770 	   assert(nrows <= ncols);
8771 	   SCIP_CALL( SCIPlpiLoadColLP(*lp, SCIP_OBJSEN_MINIMIZE,
8772 	      (int)ncols, obj, lb, ub, NULL,
8773 	      (int)nrows, lb, lb, NULL,
8774 	      (int)nnonz, beg, ind, val) );
8775 	
8776 	   /* for the last row, we can set the rhs to 1.0 already */
8777 	   ind[0] = (int)nrows - 1;
8778 	   val[0] = 1.0;
8779 	   SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8780 	
8781 	   /* free allocated memory */
8782 	   SCIPfreeBufferArray(scip, &ind);
8783 	   SCIPfreeBufferArray(scip, &val);
8784 	   SCIPfreeBufferArray(scip, &beg);
8785 	   SCIPfreeBufferArray(scip, &ub);
8786 	   SCIPfreeBufferArray(scip, &lb);
8787 	   SCIPfreeBufferArray(scip, &obj);
8788 	
8789 	   return SCIP_OKAY;
8790 	}
8791 	
8792 	/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8793 	 * \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
8794 	 * set of vertices of the domain
8795 	 */
8796 	static
8797 	SCIP_Real computeVertexPolyhedralMaxFacetError(
8798 	   SCIP*                 scip,               /**< SCIP data structure */
8799 	   SCIP_Bool             overestimate,       /**< whether we check for an over or underestimator */
8800 	   SCIP_Real*            funvals,            /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8801 	   SCIP_Real*            box,                /**< box for which facet was computed, length: 2*nallvars */
8802 	   int                   nallvars,           /**< number of all variables */
8803 	   int                   nvars,              /**< number of unfixed variables */
8804 	   int*                  nonfixedpos,        /**< indices of unfixed variables, length: nvars */
8805 	   SCIP_Real*            facetcoefs,         /**< current facet candidate's coefficients, length: nallvars */
8806 	   SCIP_Real             facetconstant       /**< current facet candidate's constant, length: nallvars */
8807 	   )
8808 	{
8809 	   SCIP_Real maxerror;
8810 	   SCIP_Real facetval;
8811 	   SCIP_Real funval;
8812 	   SCIP_Real error;
8813 	   unsigned int i;
8814 	   unsigned int ncorners;
8815 	   unsigned int prev;
8816 	
8817 	   assert(scip != NULL);
8818 	   assert(funvals != NULL);
8819 	   assert(box != NULL);
8820 	   assert(nonfixedpos != NULL);
8821 	   assert(facetcoefs != NULL);
8822 	
8823 	   ncorners = POWEROFTWO(nvars);
8824 	   maxerror = 0.0;
8825 	
8826 	   /* check the origin (all variables at lower bound) */
8827 	   facetval = facetconstant;
8828 	   for( i = 0; i < (unsigned int) nallvars; ++i )
8829 	      facetval += facetcoefs[i] * box[2*i];
8830 	
8831 	   /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8832 	   funval = funvals[0];
8833 	   if( overestimate )
8834 	      error = funval - facetval;
8835 	   else
8836 	      error = facetval - funval;
8837 	
8838 	   /* update maximum error */
8839 	   maxerror = MAX(error, maxerror);
8840 	
8841 	   prev = 0;
8842 	   for( i = 1; i < ncorners; ++i )
8843 	   {
8844 	      unsigned int gray;
8845 	      unsigned int diff;
8846 	      unsigned int pos;
8847 	      int origpos;
8848 	
8849 	      gray = i ^ (i >> 1);
8850 	      diff = gray ^ prev;
8851 	
8852 	      /* compute position of unique 1 of diff */
8853 	      pos = 0;
8854 	      while( (diff >>= 1) != 0 )
8855 	         ++pos;
8856 	      assert(pos < (unsigned int)nvars);
8857 	
8858 	      origpos = nonfixedpos[pos];
8859 	
8860 	      if( gray > prev )
8861 	         facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8862 	      else
8863 	         facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8864 	
8865 	      /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8866 	      funval = funvals[gray];
8867 	      if( overestimate )
8868 	         error = funval - facetval;
8869 	      else
8870 	         error = facetval - funval;
8871 	
8872 	      /* update  maximum error */
8873 	      maxerror = MAX(error, maxerror);
8874 	
8875 	      prev = gray;
8876 	   }
8877 	
8878 	   SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8879 	
8880 	   return maxerror;
8881 	}
8882 	
8883 	/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */  /*lint -e{715}*/
8884 	static
8885 	SCIP_RETCODE computeVertexPolyhedralFacetLP(
8886 	   SCIP*                 scip,               /**< SCIP data structure */
8887 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
8888 	   SCIP_Bool             overestimate,       /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8889 	   SCIP_Real*            xstar,              /**< point to be separated */
8890 	   SCIP_Real*            box,                /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8891 	   int                   nallvars,           /**< half of the length of box */
8892 	   int*                  nonfixedpos,        /**< indices of nonfixed variables */
8893 	   SCIP_Real*            funvals,            /**< values of function in all corner points (w.r.t. nonfixed variables) */
8894 	   int                   nvars,              /**< number of nonfixed variables */
8895 	   SCIP_Real             targetvalue,        /**< target value: no need to compute facet if value in xstar would be worse than this value */
8896 	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
8897 	   SCIP_Real*            facetcoefs,         /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8898 	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
8899 	   )
8900 	{  /*lint --e{715}*/
8901 	   SCIP_CONSHDLRDATA* conshdlrdata;
8902 	   SCIP_LPI* lp;
8903 	   SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8904 	   int* inds;
8905 	   int ncols;
8906 	   int nrows;
8907 	   int i;
8908 	   SCIP_Real facetvalue;
8909 	   SCIP_Real mindomwidth;
8910 	   SCIP_RETCODE lpsolveretcode;
8911 	
8912 	   assert(scip != NULL);
8913 	   assert(conshdlr != NULL);
8914 	   assert(xstar != NULL);
8915 	   assert(box != NULL);
8916 	   assert(nonfixedpos != NULL);
8917 	   assert(funvals != NULL);
8918 	   assert(nvars >= 0);
8919 	   assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8920 	   assert(success != NULL);
8921 	   assert(facetcoefs != NULL);
8922 	   assert(facetconstant != NULL);
8923 	
8924 	   *success = FALSE;
8925 	
8926 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8927 	   assert(conshdlrdata != NULL);
8928 	
8929 	   if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8930 	   {
8931 	      SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8932 	   }
8933 	
8934 	   /* construct an LP for this size, if not having one already */
8935 	   if( conshdlrdata->vp_lp[nvars] == NULL )
8936 	   {
8937 	      SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8938 	   }
8939 	   lp = conshdlrdata->vp_lp[nvars];
8940 	   assert(lp != NULL);
8941 	
8942 	   /* get number of cols and rows of separation lp */
8943 	   SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8944 	   SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8945 	
8946 	   /* number of columns should equal the number of corners = 2^nvars */
8947 	   assert(ncols == (int)POWEROFTWO(nvars));
8948 	
8949 	   /* allocate necessary memory */
8950 	   SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8951 	   SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8952 	
8953 	   /*
8954 	    * set up the described LP on the transformed space
8955 	    */
8956 	
8957 	   for( i = 0; i < ncols; ++i )
8958 	      inds[i] = i;
8959 	
8960 	   /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
8961 	   mindomwidth = 2*SCIPinfinity(scip);
8962 	   for( i = 0; i < nrows-1; ++i )
8963 	   {
8964 	      SCIP_Real solval;
8965 	      SCIP_Real lb;
8966 	      SCIP_Real ub;
8967 	      int varpos;
8968 	
8969 	      assert(i < nvars);
8970 	
8971 	      varpos = nonfixedpos[i];
8972 	      lb = box[2 * varpos];
8973 	      ub = box[2 * varpos + 1];
8974 	      solval = xstar[varpos];
8975 	
8976 	      if( ub - lb < mindomwidth )
8977 	         mindomwidth = ub - lb;
8978 	
8979 	      /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
8980 	      if( solval <= lb )
8981 	         aux[i] = 0.0;
8982 	      else if( solval >= ub )
8983 	         aux[i] = 1.0;
8984 	      else
8985 	         aux[i] = (solval - lb) / (ub - lb);
8986 	
8987 	      /* perturb point to hopefully obtain a facet of the convex envelope */
8988 	      if( conshdlrdata->vp_maxperturb > 0.0 )
8989 	      {
8990 	         assert(conshdlrdata->vp_randnumgen != NULL);
8991 	
8992 	         if( aux[i] == 1.0 )
8993 	            aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
8994 	         else if( aux[i] == 0.0 )
8995 	            aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
8996 	         else
8997 	         {
8998 	            SCIP_Real perturbation;
8999 	
9000 	            perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9001 	            perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9002 	            aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9003 	         }
9004 	         assert(0.0 < aux[i] && aux[i] < 1.0);
9005 	      }
9006 	
9007 	      SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9008 	   }
9009 	
9010 	   /* update LP */
9011 	   SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9012 	   SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9013 	   SCIP_CALL( SCIPlpiChgObjsen(lp, overestimate ? SCIP_OBJSEN_MAXIMIZE : SCIP_OBJSEN_MINIMIZE) );
9014 	
9015 	   /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9016 	   if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9017 	   {
9018 	      SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9019 	   }
9020 	   /* set an iteration limit so we do not run forever */
9021 	   SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPITLIM, 100*ncols) );
9022 	   /* 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 */
9023 	   SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_FEASTOL, SCIPfeastol(scip)) );
9024 	   /* since we work with the dual of the LP, dual feastol determines validity of the facet
9025 	    * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9026 	    * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9027 	    */
9028 	   SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, MIN(SCIPfeastol(scip), MAX(SCIPepsilon(scip), mindomwidth * SCIPfeastol(scip)))) );
9029 	
9030 	#ifdef SCIP_DEBUG
9031 	   SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPINFO, 1) );
9032 	#endif
9033 	
9034 	   /*
9035 	    * solve the LP and store the resulting facet for the transformed space
9036 	    */
9037 	   if( conshdlrdata->vp_dualsimplex )
9038 	   {
9039 	      lpsolveretcode = SCIPlpiSolveDual(lp);
9040 	   }
9041 	   else
9042 	   {
9043 	      lpsolveretcode = SCIPlpiSolvePrimal(lp);
9044 	   }
9045 	   if( lpsolveretcode == SCIP_LPERROR )
9046 	   {
9047 	      SCIPdebugMsg(scip, "LP error, aborting.\n");
9048 	      goto CLEANUP;
9049 	   }
9050 	   SCIP_CALL( lpsolveretcode );
9051 	
9052 	   /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9053 	   if( !SCIPlpiIsDualFeasible(lp) )
9054 	   {
9055 	      SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9056 	      goto CLEANUP;
9057 	   }
9058 	
9059 	   /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9060 	    * columns than needed, in particular, \bar \beta is the last dual multiplier
9061 	    */
9062 	   SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9063 	
9064 	   for( i = 0; i < nvars; ++i )
9065 	      facetcoefs[nonfixedpos[i]] = aux[i];
9066 	   /* last dual multiplier is the constant */
9067 	   *facetconstant = aux[nrows - 1];
9068 	
9069 	#ifdef SCIP_DEBUG
9070 	   SCIPdebugMsg(scip, "facet for the transformed problem: ");
9071 	   for( i = 0; i < nallvars; ++i )
9072 	   {
9073 	      SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9074 	   }
9075 	   SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9076 	#endif
9077 	
9078 	   /*
9079 	    * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9080 	    */
9081 	
9082 	   SCIPdebugMsg(scip, "facet in orig. space: ");
9083 	
9084 	   facetvalue = 0.0;
9085 	   for( i = 0; i < nvars; ++i )
9086 	   {
9087 	      SCIP_Real lb;
9088 	      SCIP_Real ub;
9089 	      int varpos;
9090 	
9091 	      varpos = nonfixedpos[i];
9092 	      lb = box[2 * varpos];
9093 	      ub = box[2 * varpos + 1];
9094 	      assert(!SCIPisEQ(scip, lb, ub));
9095 	
9096 	      /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9097 	      facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9098 	
9099 	      /* beta = beta_bar - sum_i alpha_i * lb_i */
9100 	      *facetconstant -= facetcoefs[varpos] * lb;
9101 	
9102 	      /* evaluate */
9103 	      facetvalue += facetcoefs[varpos] * xstar[varpos];
9104 	
9105 	      SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9106 	   }
9107 	   SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9108 	
9109 	   /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9110 	   facetvalue += *facetconstant;
9111 	
9112 	   SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9113 	
9114 	    /* if overestimate, then we want facetvalue < targetvalue
9115 	    * if underestimate, then we want facetvalue > targetvalue
9116 	    * if none holds, give up
9117 	    * so maybe here we should check against the minimal violation
9118 	    */
9119 	   if( overestimate == (facetvalue > targetvalue) )
9120 	   {
9121 	      SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9122 	      goto CLEANUP;
9123 	   }
9124 	
9125 	   /* if we made it until here, then we have a nice facet */
9126 	   *success = TRUE;
9127 	
9128 	CLEANUP:
9129 	   /* free allocated memory */
9130 	   SCIPfreeBufferArray(scip, &inds);
9131 	   SCIPfreeBufferArray(scip, &aux);
9132 	
9133 	   return SCIP_OKAY;
9134 	}
9135 	
9136 	/** computes a facet of the convex or concave envelope of a univariant vertex polyhedral function
9137 	 *
9138 	 * In other words, compute the line that passes through two given points.
9139 	 */
9140 	static
9141 	SCIP_RETCODE computeVertexPolyhedralFacetUnivariate(
9142 	   SCIP*                 scip,               /**< SCIP data structure */
9143 	   SCIP_Real             left,               /**< left coordinate */
9144 	   SCIP_Real             right,              /**< right coordinate */
9145 	   SCIP_Real             funleft,            /**< value of function in left coordinate */
9146 	   SCIP_Real             funright,           /**< value of function in right coordinate */
9147 	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
9148 	   SCIP_Real*            facetcoef,          /**< buffer to store coefficient of facet defining inequality */
9149 	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
9150 	   )
9151 	{
9152 	   assert(scip != NULL);
9153 	   assert(SCIPisLE(scip, left, right));
9154 	   assert(!SCIPisInfinity(scip, -left));
9155 	   assert(!SCIPisInfinity(scip, right));
9156 	   assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9157 	   assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9158 	   assert(success != NULL);
9159 	   assert(facetcoef != NULL);
9160 	   assert(facetconstant != NULL);
9161 	
9162 	   *facetcoef = (funright - funleft) / (right - left);
9163 	   *facetconstant = funleft - *facetcoef * left;
9164 	
9165 	   *success = TRUE;
9166 	
9167 	   return SCIP_OKAY;
9168 	}
9169 	
9170 	/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9171 	 *
9172 	 * Three points a, b, and c are given.
9173 	 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9174 	 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9175 	 */
9176 	static
9177 	SCIP_RETCODE computeHyperplaneThreePoints(
9178 	   SCIP*                 scip,               /**< SCIP data structure */
9179 	   SCIP_Real             a1,                 /**< first coordinate of a */
9180 	   SCIP_Real             a2,                 /**< second coordinate of a */
9181 	   SCIP_Real             a3,                 /**< third coordinate of a */
9182 	   SCIP_Real             b1,                 /**< first coordinate of b */
9183 	   SCIP_Real             b2,                 /**< second coordinate of b */
9184 	   SCIP_Real             b3,                 /**< third coordinate of b */
9185 	   SCIP_Real             c1,                 /**< first coordinate of c */
9186 	   SCIP_Real             c2,                 /**< second coordinate of c */
9187 	   SCIP_Real             c3,                 /**< third coordinate of c */
9188 	   SCIP_Real*            alpha,              /**< coefficient of first coordinate */
9189 	   SCIP_Real*            beta,               /**< coefficient of second coordinate */
9190 	   SCIP_Real*            gamma_,             /**< coefficient of third coordinate */
9191 	   SCIP_Real*            delta               /**< constant right-hand side */
9192 	   )
9193 	{
9194 	   assert(scip != NULL);
9195 	   assert(alpha != NULL);
9196 	   assert(beta  != NULL);
9197 	   assert(gamma_ != NULL);
9198 	   assert(delta != NULL);
9199 	
9200 	   *alpha  = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9201 	   *beta   = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9202 	   *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9203 	   *delta  = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9204 	
9205 	   /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9206 	
9207 	   if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9208 	      SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9209 	      SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9210 	   {
9211 	      SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9212 	      *delta  = 0.0;
9213 	      *alpha  = 0.0;
9214 	      *beta   = 0.0;
9215 	      *gamma_ = 0.0;
9216 	      return SCIP_OKAY;
9217 	   }
9218 	
9219 	   /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9220 	   if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9221 	      !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9222 	      !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9223 	   {
9224 	      SCIP_Real m[9];
9225 	      SCIP_Real rhs[3];
9226 	      SCIP_Real x[3];
9227 	      SCIP_Bool success;
9228 	
9229 	      /*
9230 	      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));
9231 	      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));
9232 	      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));
9233 	      */
9234 	
9235 	      /* initialize matrix column-wise */
9236 	      m[0] = a1;
9237 	      m[1] = b1;
9238 	      m[2] = c1;
9239 	      m[3] = a2;
9240 	      m[4] = b2;
9241 	      m[5] = c2;
9242 	      m[6] = a3;
9243 	      m[7] = b3;
9244 	      m[8] = c3;
9245 	
9246 	      rhs[0] = 1.0;
9247 	      rhs[1] = 1.0;
9248 	      rhs[2] = 1.0;
9249 	
9250 	      SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9251 	
9252 	      /* solve the linear problem */
9253 	      SCIP_CALL( SCIPsolveLinearEquationsIpopt(3, m, rhs, x, &success) );
9254 	
9255 	      *delta  = rhs[0];
9256 	      *alpha  = x[0];
9257 	      *beta   = x[1];
9258 	      *gamma_ = x[2];
9259 	
9260 	      /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9261 	       * not add a cut to SCIP and that all assertions are trivially fulfilled
9262 	       */
9263 	      if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9264 	         !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9265 	         !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9266 	      {
9267 	         SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9268 	         *delta  = 0.0;
9269 	         *alpha  = 0.0;
9270 	         *beta   = 0.0;
9271 	         *gamma_ = 0.0;
9272 	      }
9273 	   }
9274 	
9275 	   if( *gamma_ < 0.0 )
9276 	   {
9277 	      *alpha  = -*alpha;
9278 	      *beta   = -*beta;
9279 	      *gamma_ = -*gamma_;
9280 	      *delta  = -*delta;
9281 	   }
9282 	
9283 	   return SCIP_OKAY;
9284 	}
9285 	
9286 	/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9287 	static
9288 	SCIP_RETCODE computeVertexPolyhedralFacetBivariate(
9289 	   SCIP*                 scip,               /**< SCIP data structure */
9290 	   SCIP_Bool             overestimate,       /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9291 	   SCIP_Real             p1[2],              /**< first vertex of box */
9292 	   SCIP_Real             p2[2],              /**< second vertex of box */
9293 	   SCIP_Real             p3[2],              /**< third vertex of box */
9294 	   SCIP_Real             p4[2],              /**< forth vertex of box */
9295 	   SCIP_Real             p1val,              /**< value in p1 */
9296 	   SCIP_Real             p2val,              /**< value in p2 */
9297 	   SCIP_Real             p3val,              /**< value in p3 */
9298 	   SCIP_Real             p4val,              /**< value in p4 */
9299 	   SCIP_Real             xstar[2],           /**< point to be separated */
9300 	   SCIP_Real             targetvalue,        /**< target value: no need to compute facet if value in xstar would be worse than this value */
9301 	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
9302 	   SCIP_Real*            facetcoefs,         /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9303 	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
9304 	   )
9305 	{
9306 	   SCIP_Real alpha, beta, gamma_, delta;
9307 	   SCIP_Real xstarval, candxstarval = 0.0;
9308 	   int leaveout;
9309 	
9310 	   assert(scip != NULL);
9311 	   assert(success != NULL);
9312 	   assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9313 	   assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9314 	   assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9315 	   assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9316 	   assert(facetcoefs != NULL);
9317 	   assert(facetconstant != NULL);
9318 	
9319 	   *success = FALSE;
9320 	
9321 	   /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9322 	   if( !overestimate )
9323 	   {
9324 	      p1val = -p1val;
9325 	      p2val = -p2val;
9326 	      p3val = -p3val;
9327 	      p4val = -p4val;
9328 	      targetvalue = -targetvalue;
9329 	   }
9330 	
9331 	   SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9332 	   SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9333 	   SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9334 	   SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9335 	
9336 	   /* Compute coefficients alpha, beta, gamma (>0), delta such that
9337 	    *   alpha*x + beta*y + gamma*z = delta
9338 	    * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9339 	    * the fourth corner point lies below this hyperplane.
9340 	    * 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.,
9341 	    *    alpha*x + beta*y - delta <= -gamma * f(x,y),
9342 	    * or, equivalently,
9343 	    *   -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9344 	    */
9345 	   for( leaveout = 1; leaveout <= 4; ++leaveout )
9346 	   {
9347 	      switch( leaveout)
9348 	      {
9349 	         case 1 :
9350 	            /* get hyperplane through p2, p3, p4 */
9351 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9352 	               &alpha, &beta, &gamma_, &delta) );
9353 	            /* if not underestimating in p1, then go to next candidate */
9354 	            if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9355 	               continue;
9356 	            break;
9357 	
9358 	         case 2 :
9359 	            /* get hyperplane through p1, p3, p4 */
9360 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9361 	               &alpha, &beta, &gamma_, &delta) );
9362 	            /* if not underestimating in p2, then go to next candidate */
9363 	            if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9364 	               continue;
9365 	            break;
9366 	
9367 	         case 3 :
9368 	            /* get hyperplane through p1, p2, p4 */
9369 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9370 	               &alpha, &beta, &gamma_, &delta) );
9371 	            /* if not underestimating in p3, then go to next candidate */
9372 	            if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9373 	               continue;
9374 	            break;
9375 	
9376 	         case 4 :
9377 	            /* get hyperplane through p1, p2, p3 */
9378 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9379 	               &alpha, &beta, &gamma_, &delta) );
9380 	            /* if not underestimating in p4, then stop */
9381 	            if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9382 	               continue;
9383 	            break;
9384 	
9385 	         default: /* only for lint */
9386 	            alpha = SCIP_INVALID;
9387 	            beta = SCIP_INVALID;
9388 	            gamma_ =  SCIP_INVALID;
9389 	            delta = SCIP_INVALID;
9390 	            break;
9391 	      }
9392 	
9393 	      /* check if bad luck: should not happen if numerics are fine */
9394 	      if( SCIPisZero(scip, gamma_) )
9395 	         continue;
9396 	      assert(!SCIPisNegative(scip, gamma_));
9397 	
9398 	      /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9399 	      if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9400 	         ( !SCIPisZero(scip, beta)  && SCIPisZero(scip, beta/gamma_)) )
9401 	         continue;
9402 	
9403 	      SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9404 	
9405 	      /* value of hyperplane candidate in xstar */
9406 	      xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9407 	
9408 	      /* if reaching target and first or better than previous candidate, then update */
9409 	      if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9410 	      {
9411 	         /* flip hyperplane */
9412 	         if( !overestimate )
9413 	            gamma_ = -gamma_;
9414 	
9415 	         facetcoefs[0] = -alpha/gamma_;
9416 	         facetcoefs[1] = -beta/gamma_;
9417 	         *facetconstant = delta/gamma_;
9418 	
9419 	         *success = TRUE;
9420 	         candxstarval = xstarval;
9421 	      }
9422 	   }
9423 	
9424 	   return SCIP_OKAY;
9425 	}
9426 	
9427 	/*
9428 	 * Callback methods of constraint handler
9429 	 */
9430 	
9431 	/** copy method for constraint handler plugins (called when SCIP copies plugins) */
9432 	static
9433 	SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
9434 	{  /*lint --e{715}*/
9435 	   SCIP_CONSHDLR*     targetconshdlr;
9436 	   SCIP_CONSHDLRDATA* sourceconshdlrdata;
9437 	   int                i;
9438 	
9439 	   assert(scip != NULL);
9440 	   assert(conshdlr != NULL);
9441 	   assert(valid != NULL);
9442 	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
9443 	
9444 	   /* create basic data of constraint handler and include it to scip */
9445 	   SCIP_CALL( SCIPincludeConshdlrNonlinear(scip) );
9446 	
9447 	   targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9448 	   assert(targetconshdlr != NULL);
9449 	   assert(targetconshdlr != conshdlr);
9450 	
9451 	   sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
9452 	   assert(sourceconshdlrdata != NULL);
9453 	
9454 	   /* copy nonlinear handlers */
9455 	   for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
9456 	   {
9457 	      SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
9458 	   }
9459 	
9460 	   *valid = TRUE;
9461 	
9462 	   return SCIP_OKAY;
9463 	}
9464 	
9465 	/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9466 	static
9467 	SCIP_DECL_CONSFREE(consFreeNonlinear)
9468 	{  /*lint --e{715}*/
9469 	   SCIP_CONSHDLRDATA* conshdlrdata;
9470 	   int i;
9471 	
9472 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9473 	   assert(conshdlrdata != NULL);
9474 	
9475 	   /* free nonlinear handlers */
9476 	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9477 	   {
9478 	      SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
9479 	      assert(conshdlrdata->nlhdlrs[i] == NULL);
9480 	   }
9481 	   SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
9482 	   conshdlrdata->nlhdlrssize = 0;
9483 	
9484 	   /* free upgrade functions */
9485 	   for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
9486 	   {
9487 	      assert(conshdlrdata->consupgrades[i] != NULL);
9488 	      SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
9489 	   }
9490 	   SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
9491 	
9492 	   SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
9493 	
9494 	   SCIPqueueFree(&conshdlrdata->reversepropqueue);
9495 	
9496 	   if( conshdlrdata->vp_randnumgen != NULL )
9497 	      SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9498 	
9499 	   /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9500 	   for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9501 	   {
9502 	      if( conshdlrdata->vp_lp[i] != NULL )
9503 	      {
9504 	         SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9505 	      }
9506 	   }
9507 	
9508 	   assert(conshdlrdata->branchrandnumgen == NULL);
9509 	
9510 	   assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
9511 	   SCIPhashmapFree(&conshdlrdata->var2expr);
9512 	
9513 	   SCIPfreeMemory(scip, &conshdlrdata);
9514 	   SCIPconshdlrSetData(conshdlr, NULL);
9515 	
9516 	   return SCIP_OKAY;
9517 	}
9518 	
9519 	
9520 	/** initialization method of constraint handler (called after problem was transformed) */
9521 	static
9522 	SCIP_DECL_CONSINIT(consInitNonlinear)
9523 	{  /*lint --e{715}*/
9524 	   SCIP_CONSHDLRDATA* conshdlrdata;
9525 	   int i;
9526 	
9527 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9528 	   assert(conshdlrdata != NULL);
9529 	
9530 	   /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
9531 	   conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
9532 	   /* set to 1 so it is larger than initial value of lastenforound in exprs */
9533 	   conshdlrdata->enforound = 1;
9534 	
9535 	   for( i = 0; i < nconss; ++i )
9536 	   {
9537 	      SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
9538 	      SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
9539 	   }
9540 	
9541 	   /* sort nonlinear handlers by detection priority, in decreasing order */
9542 	   if( conshdlrdata->nnlhdlrs > 1 )
9543 	      SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
9544 	
9545 	   /* get heuristics for later use */
9546 	   conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9547 	   conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9548 	
9549 	   /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) */
9550 	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9551 	   {
9552 	      SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
9553 	   }
9554 	
9555 	   /* reset statistics in constraint handler */
9556 	   conshdlrdata->nweaksepa = 0;
9557 	   conshdlrdata->ntightenlp = 0;
9558 	   conshdlrdata->ndesperatebranch = 0;
9559 	   conshdlrdata->ndesperatecutoff = 0;
9560 	   conshdlrdata->ndesperatetightenlp = 0;
9561 	   conshdlrdata->nforcelp = 0;
9562 	   SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
9563 	   conshdlrdata->ncanonicalizecalls = 0;
9564 	
9565 	#ifdef ENFOLOGFILE
9566 	   ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
9567 	#endif
9568 	
9569 	   return SCIP_OKAY;
9570 	}
9571 	
9572 	
9573 	/** deinitialization method of constraint handler (called before transformed problem is freed) */
9574 	static
9575 	SCIP_DECL_CONSEXIT(consExitNonlinear)
9576 	{  /*lint --e{715}*/
9577 	   SCIP_CONSHDLRDATA* conshdlrdata;
9578 	   SCIP_CONS** consssorted;
9579 	   int i;
9580 	
9581 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9582 	   assert(conshdlrdata != NULL);
9583 	
9584 	   if( nconss > 0 )
9585 	   {
9586 	      /* for better performance of dropVarEvents, we sort by index, descending */
9587 	      SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
9588 	      SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
9589 	
9590 	      for( i = 0; i < nconss; ++i )
9591 	      {
9592 	         SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
9593 	         SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
9594 	      }
9595 	
9596 	      SCIPfreeBufferArray(scip, &consssorted);
9597 	   }
9598 	
9599 	   conshdlrdata->subnlpheur = NULL;
9600 	   conshdlrdata->trysolheur = NULL;
9601 	
9602 	   if( conshdlrdata->vp_randnumgen != NULL )
9603 	      SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9604 	
9605 	   /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9606 	   for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9607 	   {
9608 	      if( conshdlrdata->vp_lp[i] != NULL )
9609 	      {
9610 	         SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9611 	      }
9612 	   }
9613 	
9614 	   if( conshdlrdata->branchrandnumgen != NULL )
9615 	      SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
9616 	
9617 	   /* deinitialize nonlinear handlers */
9618 	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9619 	   {
9620 	      SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
9621 	   }
9622 	
9623 	   ENFOLOG(
9624 	   if( enfologfile != NULL )
9625 	   {
9626 	      fclose(enfologfile);
9627 	      enfologfile = NULL;
9628 	   })
9629 	
9630 	   return SCIP_OKAY;
9631 	}
9632 	
9633 	
9634 	/** presolving initialization method of constraint handler (called when presolving is about to begin) */
9635 	#ifdef SCIP_DISABLED_CODE
9636 	static
9637 	SCIP_DECL_CONSINITPRE(consInitpreNonlinear)
9638 	{  /*lint --e{715}*/
9639 	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
9640 	   SCIPABORT(); /*lint --e{527}*/
9641 	
9642 	   return SCIP_OKAY;
9643 	}
9644 	#else
9645 	#define consInitpreNonlinear NULL
9646 	#endif
9647 	
9648 	
9649 	/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9650 	static
9651 	SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
9652 	{  /*lint --e{715}*/
9653 	   SCIP_Bool infeasible;
9654 	
9655 	   if( nconss == 0 )
9656 	      return SCIP_OKAY;
9657 	
9658 	   /* skip some extra work if already known to be infeasible */
9659 	   if( SCIPgetStatus(scip) == SCIP_STATUS_INFEASIBLE )
9660 	      return SCIP_OKAY;
9661 	
9662 	   /* simplify constraints and replace common subexpressions */
9663 	   SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
9664 	
9665 	   /* currently SCIP does not offer to communicate this,
9666 	    * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
9667 	    * or if a constraint expression became constant
9668 	    */
9669 	   assert(!infeasible);
9670 	
9671 	   /* tell SCIP that we have something nonlinear */
9672 	   SCIPenableNLP(scip);
9673 	
9674 	   return SCIP_OKAY;
9675 	}
9676 	
9677 	
9678 	/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
9679 	static
9680 	SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
9681 	{  /*lint --e{715}*/
9682 	   SCIP_CONSHDLRDATA* conshdlrdata;
9683 	   int i;
9684 	
9685 	   /* skip remaining initializations if we have solved already
9686 	    * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
9687 	    * assumes nonempty activities in expressions
9688 	    */
9689 	   switch( SCIPgetStatus(scip) )
9690 	   {
9691 	      case SCIP_STATUS_OPTIMAL:
9692 	      case SCIP_STATUS_INFEASIBLE:
9693 	      case SCIP_STATUS_UNBOUNDED:
9694 	      case SCIP_STATUS_INFORUNBD:
9695 	         return SCIP_OKAY;
9696 	      default: ;
9697 	   } /*lint !e788 */
9698 	
9699 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9700 	   assert(conshdlrdata != NULL);
9701 	
9702 	   /* reset one of the number of detections counter to count only current round */
9703 	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9704 	      SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
9705 	
9706 	   SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
9707 	
9708 	   /* catch new solution event */
9709 	   if( nconss != 0 && conshdlrdata->linearizeheursol != 'o' )
9710 	   {
9711 	      SCIP_EVENTHDLR* eventhdlr;
9712 	
9713 	      eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9714 	      assert(eventhdlr != NULL);
9715 	
9716 	      SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
9717 	         eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9718 	   }
9719 	
9720 	   /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
9721 	   if( conshdlrdata->branchpscostweight > 0.0 )
9722 	   {
9723 	      SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
9724 	      if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
9725 	      {
9726 	         SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
9727 	         SCIPABORT();
9728 	         return SCIP_INVALIDDATA;
9729 	      }
9730 	   }
9731 	
9732 	   return SCIP_OKAY;
9733 	}
9734 	
9735 	
9736 	/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9737 	static
9738 	SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
9739 	{  /*lint --e{715}*/
9740 	   SCIP_CONSHDLRDATA* conshdlrdata;
9741 	
9742 	   SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
9743 	
9744 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9745 	   assert(conshdlrdata != NULL);
9746 	
9747 	   /* free hash table for bilinear terms */
9748 	   SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
9749 	
9750 	   /* reset flag to allow another call of presolSingleLockedVars() after a restart */
9751 	   conshdlrdata->checkedvarlocks = FALSE;
9752 	
9753 	   /* drop catching new solution event, if catched before */
9754 	   if( conshdlrdata->newsoleventfilterpos >= 0 )
9755 	   {
9756 	      SCIP_EVENTHDLR* eventhdlr;
9757 	
9758 	      eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9759 	      assert(eventhdlr != NULL);
9760 	
9761 	      SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9762 	      conshdlrdata->newsoleventfilterpos = -1;
9763 	   }
9764 	
9765 	   return SCIP_OKAY;
9766 	}
9767 	
9768 	
9769 	/** frees specific constraint data */
9770 	static
9771 	SCIP_DECL_CONSDELETE(consDeleteNonlinear)
9772 	{  /*lint --e{715}*/
9773 	   assert(consdata != NULL);
9774 	   assert(*consdata != NULL);
9775 	   assert((*consdata)->expr != NULL);
9776 	
9777 	   /* constraint locks should have been removed */
9778 	   assert((*consdata)->nlockspos == 0);
9779 	   assert((*consdata)->nlocksneg == 0);
9780 	
9781 	   /* free variable expressions */
9782 	   SCIP_CALL( freeVarExprs(scip, *consdata) );
9783 	
9784 	   SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
9785 	
9786 	   /* free nonlinear row representation */
9787 	   if( (*consdata)->nlrow != NULL )
9788 	   {
9789 	      SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
9790 	   }
9791 	
9792 	   SCIPfreeBlockMemory(scip, consdata);
9793 	
9794 	   return SCIP_OKAY;
9795 	}
9796 	
9797 	
9798 	/** transforms constraint data into data belonging to the transformed problem */
9799 	static
9800 	SCIP_DECL_CONSTRANS(consTransNonlinear)
9801 	{  /*lint --e{715}*/
9802 	   SCIP_EXPR* targetexpr;
9803 	   SCIP_CONSDATA* sourcedata;
9804 	
9805 	   sourcedata = SCIPconsGetData(sourcecons);
9806 	   assert(sourcedata != NULL);
9807 	
9808 	   /* get a copy of sourceexpr with transformed vars */
9809 	   SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
9810 	   assert(targetexpr != NULL);  /* SCIPduplicateExpr cannot fail */
9811 	
9812 	   /* create transformed cons (only captures targetexpr, no need to copy again) */
9813 	   SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
9814 	      targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
9815 	      SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
9816 	      SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
9817 	      SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
9818 	      SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
9819 	
9820 	   /* release target expr */
9821 	   SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
9822 	
9823 	   return SCIP_OKAY;
9824 	}
9825 	
9826 	
9827 	/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9828 	static
9829 	SCIP_DECL_CONSINITLP(consInitlpNonlinear)
9830 	{  /*lint --e{715}*/
9831 	   /* create auxiliary variables and call separation initialization callbacks of the expression handlers
9832 	    * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
9833 	    *   during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
9834 	    *   for now, there is an assert in detectNlhdlrs to require initial if separated
9835 	    */
9836 	   SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
9837 	
9838 	   /* collect all bilinear terms for which an auxvar is present
9839 	    * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
9840 	    * addition (and removal?) of constraints during solve
9841 	    * this is typically the majority of constraints, but the method should be made more flexible
9842 	    */
9843 	   SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
9844 	
9845 	   return SCIP_OKAY;
9846 	}
9847 	
9848 	
9849 	/** separation method of constraint handler for LP solutions */
9850 	static
9851 	SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
9852 	{  /*lint --e{715}*/
9853 	   SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
9854 	
9855 	   return SCIP_OKAY;
9856 	}
9857 	
9858 	
9859 	/** separation method of constraint handler for arbitrary primal solutions */
9860 	static
9861 	SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
9862 	{  /*lint --e{715}*/
9863 	   SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
9864 	
9865 	   return SCIP_OKAY;
9866 	}
9867 	
9868 	
9869 	/** constraint enforcing method of constraint handler for LP solutions */
9870 	static
9871 	SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
9872 	{  /*lint --e{715}*/
9873 	   SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
9874 	
9875 	   return SCIP_OKAY;
9876 	}
9877 	
9878 	
9879 	/** constraint enforcing method of constraint handler for relaxation solutions */
9880 	static
9881 	SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
9882 	{  /*lint --e{715}*/
9883 	   SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
9884 	
9885 	   return SCIP_OKAY;
9886 	}
9887 	
9888 	
9889 	/** constraint enforcing method of constraint handler for pseudo solutions */
9890 	static
9891 	SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
9892 	{  /*lint --e{715}*/
9893 	   SCIP_RESULT propresult;
9894 	   SCIP_Longint soltag;
9895 	   int nchgbds;
9896 	   int nnotify;
9897 	   int c;
9898 	
9899 	   soltag = SCIPgetExprNewSoltag(scip);
9900 	
9901 	   *result = SCIP_FEASIBLE;
9902 	   for( c = 0; c < nconss; ++c )
9903 	   {
9904 	      SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
9905 	
9906 	      if( isConsViolated(scip, conss[c]) )
9907 	         *result = SCIP_INFEASIBLE;
9908 	   }
9909 	
9910 	   if( *result == SCIP_FEASIBLE )
9911 	      return SCIP_OKAY;
9912 	
9913 	   /* try to propagate
9914 	    * TODO obey propinenfo parameter, but we need something to recognize cutoff
9915 	    */
9916 	   nchgbds = 0;
9917 	   SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
9918 	
9919 	   if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
9920 	   {
9921 	      *result = propresult;
9922 	      return SCIP_OKAY;
9923 	   }
9924 	
9925 	   /* register all unfixed variables in all violated constraints as branching candidates */
9926 	   SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
9927 	   if( nnotify > 0 )
9928 	   {
9929 	      SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
9930 	
9931 	      return SCIP_OKAY;
9932 	   }
9933 	
9934 	   SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
9935 	   *result = SCIP_SOLVELP;
9936 	   ++SCIPconshdlrGetData(conshdlr)->nforcelp;
9937 	
9938 	   return SCIP_OKAY;
9939 	}
9940 	
9941 	
9942 	/** feasibility check method of constraint handler for integral solutions */
9943 	static
9944 	SCIP_DECL_CONSCHECK(consCheckNonlinear)
9945 	{  /*lint --e{715}*/
9946 	   SCIP_CONSHDLRDATA* conshdlrdata;
9947 	   SCIP_CONSDATA*     consdata;
9948 	   SCIP_Real          maxviol;
9949 	   SCIP_Bool          maypropfeasible;
9950 	   SCIP_Longint       soltag;
9951 	   int c;
9952 	
9953 	   assert(scip != NULL);
9954 	   assert(conshdlr != NULL);
9955 	   assert(conss != NULL || nconss == 0);
9956 	   assert(result != NULL);
9957 	
9958 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
9959 	   assert(conshdlrdata != NULL);
9960 	
9961 	   *result = SCIP_FEASIBLE;
9962 	   soltag = SCIPgetExprNewSoltag(scip);
9963 	   maxviol = 0.0;
9964 	   maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
9965 	      && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING;
9966 	
9967 	   /* check nonlinear constraints for feasibility */
9968 	   for( c = 0; c < nconss; ++c )
9969 	   {
9970 	      assert(conss != NULL && conss[c] != NULL);
9971 	      SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
9972 	
9973 	      if( isConsViolated(scip, conss[c]) )
9974 	      {
9975 	         *result = SCIP_INFEASIBLE;
9976 	         maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
9977 	
9978 	         consdata = SCIPconsGetData(conss[c]);
9979 	         assert(consdata != NULL);
9980 	
9981 	         /* print reason for infeasibility */
9982 	         if( printreason )
9983 	         {
9984 	            SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
9985 	            SCIPinfoMessage(scip, NULL, ";\n");
9986 	
9987 	            if( consdata->lhsviol > SCIPfeastol(scip) )
9988 	            {
9989 	               SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
9990 	            }
9991 	            if( consdata->rhsviol > SCIPfeastol(scip) )
9992 	            {
9993 	               SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
9994 	            }
9995 	         }
9996 	         else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
9997 	         {
9998 	            /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
9999 	            return SCIP_OKAY;
10000	         }
10001	
10002	         /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
10003	         if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
10004	            maypropfeasible = FALSE;
10005	
10006	         if( maypropfeasible )
10007	         {
10008	            if( consdata->lhsviol > SCIPfeastol(scip) )
10009	            {
10010	               /* check if there is a variable which may help to get the left hand side satisfied
10011	                * if there is no such variable, then we cannot get feasible
10012	                */
10013	               if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
10014	                   !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
10015	                  maypropfeasible = FALSE;
10016	            }
10017	            else
10018	            {
10019	               assert(consdata->rhsviol > SCIPfeastol(scip));
10020	               /* check if there is a variable which may help to get the right hand side satisfied
10021	                * if there is no such variable, then we cannot get feasible
10022	                */
10023	               if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
10024	                   !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
10025	                  maypropfeasible = FALSE;
10026	            }
10027	         }
10028	      }
10029	   }
10030	
10031	   if( *result == SCIP_INFEASIBLE && maypropfeasible )
10032	   {
10033	      SCIP_Bool success;
10034	
10035	      SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
10036	
10037	      /* do not pass solution to NLP heuristic if we made it feasible this way */
10038	      if( success )
10039	         return SCIP_OKAY;
10040	   }
10041	
10042	   if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
10043	   {
10044	      SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
10045	   }
10046	
10047	   return SCIP_OKAY;
10048	}
10049	
10050	
10051	/** domain propagation method of constraint handler */
10052	static
10053	SCIP_DECL_CONSPROP(consPropNonlinear)
10054	{  /*lint --e{715}*/
10055	   int nchgbds = 0;
10056	
10057	   SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
10058	   assert(nchgbds >= 0);
10059	
10060	   /* TODO would it make sense to check for redundant constraints? */
10061	
10062	   return SCIP_OKAY;
10063	}
10064	
10065	
10066	/** presolving method of constraint handler */
10067	static
10068	SCIP_DECL_CONSPRESOL(consPresolNonlinear)
10069	{  /*lint --e{715}*/
10070	   SCIP_CONSHDLRDATA* conshdlrdata;
10071	   SCIP_Bool infeasible;
10072	   int c;
10073	
10074	   *result = SCIP_DIDNOTFIND;
10075	
10076	   if( nconss == 0 )
10077	   {
10078	      *result = SCIP_DIDNOTRUN;
10079	      return SCIP_OKAY;
10080	   }
10081	
10082	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10083	   assert(conshdlrdata != NULL);
10084	
10085	   /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
10086	   SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
10087	   if( infeasible )
10088	   {
10089	      *result = SCIP_CUTOFF;
10090	      return SCIP_OKAY;
10091	   }
10092	
10093	   /* merge constraints with the same root expression */
10094	   if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
10095	   {
10096	      SCIP_Bool success;
10097	
10098	      SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
10099	      if( success )
10100	         *result = SCIP_SUCCESS;
10101	   }
10102	
10103	   /* propagate constraints */
10104	   SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
10105	   if( *result == SCIP_CUTOFF )
10106	      return SCIP_OKAY;
10107	
10108	   /* propagate function domains (TODO integrate with simplify?) */
10109	   if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
10110	   {
10111	      SCIP_RESULT localresult;
10112	      SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
10113	      if( localresult == SCIP_CUTOFF )
10114	      {
10115	         *result = SCIP_CUTOFF;
10116	         return SCIP_OKAY;
10117	      }
10118	      if( localresult == SCIP_REDUCEDDOM )
10119	         *result = SCIP_REDUCEDDOM;
10120	   }
10121	
10122	   /* check for redundant constraints, remove constraints that are a value expression */
10123	   SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
10124	   if( infeasible )
10125	   {
10126	      *result = SCIP_CUTOFF;
10127	      return SCIP_OKAY;
10128	   }
10129	
10130	   /* try to upgrade constraints */
10131	   for( c = 0; c < nconss; ++c )
10132	   {
10133	      SCIP_Bool upgraded;
10134	
10135	      /* skip inactive and deleted constraints */
10136	      if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
10137	         continue;
10138	
10139	      SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10140	   }
10141	
10142	   /* try to change continuous variables that appear linearly to be implicit integer */
10143	   if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
10144	   {
10145	      SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
10146	
10147	      if( infeasible )
10148	      {
10149	         SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
10150	         *result = SCIP_CUTOFF;
10151	         return SCIP_OKAY;
10152	      }
10153	   }
10154	
10155	   /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
10156	   if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) && SCIPisPresolveFinished(scip)
10157	      && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
10158	   {
10159	      /* run this presolving technique only once because we don't want to generate identical bound disjunction
10160	       * constraints multiple times
10161	       */
10162	      conshdlrdata->checkedvarlocks = TRUE;
10163	
10164	      for( c = 0; c < nconss; ++c )
10165	      {
10166	         int tmpnchgvartypes = 0;
10167	         int tmpnaddconss = 0;
10168	
10169	         SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
10170	         SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
10171	            SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
10172	
10173	         if( infeasible )
10174	         {
10175	            SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
10176	            *result = SCIP_CUTOFF;
10177	            return SCIP_OKAY;
10178	         }
10179	
10180	         (*nchgvartypes) += tmpnchgvartypes;
10181	         (*naddconss) += tmpnaddconss;
10182	      }
10183	   }
10184	
10185	   if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
10186	      *result = SCIP_SUCCESS;
10187	   else
10188	      *result = SCIP_DIDNOTFIND;
10189	
10190	   return SCIP_OKAY;
10191	}
10192	
10193	
10194	/** propagation conflict resolving method of constraint handler */
10195	#ifdef SCIP_DISABLED_CODE
10196	static
10197	SCIP_DECL_CONSRESPROP(consRespropNonlinear)
10198	{  /*lint --e{715}*/
10199	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10200	   SCIPABORT(); /*lint --e{527}*/
10201	
10202	   return SCIP_OKAY;
10203	}
10204	#else
10205	#define consRespropNonlinear NULL
10206	#endif
10207	
10208	
10209	/** variable rounding lock method of constraint handler */
10210	static
10211	SCIP_DECL_CONSLOCK(consLockNonlinear)
10212	{  /*lint --e{715}*/
10213	   SCIP_CONSDATA* consdata;
10214	   SCIP_EXPR_OWNERDATA* ownerdata;
10215	   SCIP_Bool reinitsolve = FALSE;
10216	
10217	   assert(conshdlr != NULL);
10218	   assert(cons != NULL);
10219	
10220	   consdata = SCIPconsGetData(cons);
10221	   assert(consdata != NULL);
10222	   assert(consdata->expr != NULL);
10223	
10224	   ownerdata = SCIPexprGetOwnerData(consdata->expr);
10225	
10226	   /* check whether we need to initSolve again because
10227	    * - we have enfo initialized (nenfos >= 0)
10228	    * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
10229	    */
10230	   if( ownerdata->nenfos >= 0 )
10231	   {
10232	      if( (consdata->nlockspos == 0) != (nlockspos == 0) )
10233	         reinitsolve = TRUE;
10234	      if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
10235	         reinitsolve = TRUE;
10236	   }
10237	
10238	   if( reinitsolve )
10239	   {
10240	      SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10241	   }
10242	
10243	   /* add locks */
10244	   SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
10245	
10246	   if( reinitsolve )
10247	   {
10248	      SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10249	   }
10250	
10251	   return SCIP_OKAY;
10252	}
10253	
10254	
10255	/** constraint activation notification method of constraint handler */
10256	static
10257	SCIP_DECL_CONSACTIVE(consActiveNonlinear)
10258	{  /*lint --e{715}*/
10259	   SCIP_CONSDATA* consdata;
10260	   SCIP_Bool infeasible = FALSE;
10261	
10262	   consdata = SCIPconsGetData(cons);
10263	   assert(consdata != NULL);
10264	
10265	   /* simplify root expression if the constraint has been added after presolving */
10266	   if( SCIPgetStage(scip) > SCIP_STAGE_EXITPRESOLVE )
10267	   {
10268	      if( !consdata->issimplified )
10269	      {
10270	         SCIP_EXPR* simplified;
10271	         SCIP_Bool changed;
10272	
10273	         /* simplify constraint */
10274	         SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
10275	         SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
10276	         assert(simplified != NULL);
10277	         consdata->expr = simplified;
10278	         consdata->issimplified = TRUE;
10279	      }
10280	
10281	      /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
10282	      {
10283	         SCIP_CONSHDLRDATA* conshdlrdata;
10284	         SCIP_EXPRITER* it;
10285	         SCIP_EXPR* expr;
10286	
10287	         conshdlrdata = SCIPconshdlrGetData(conshdlr);
10288	         assert(conshdlrdata != NULL);
10289	
10290	         SCIP_CALL( SCIPcreateExpriter(scip, &it) );
10291	         SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
10292	         SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
10293	         for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10294	         {
10295	            SCIP_EXPR* child;
10296	            SCIP_EXPR* hashmapexpr;
10297	
10298	            child = SCIPexpriterGetChildExprDFS(it);
10299	            if( !SCIPisExprVar(scip, child) )
10300	               continue;
10301	
10302	            /* check which expression is stored in the hashmap for the var of child */
10303	            hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
10304	            /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
10305	            if( hashmapexpr != NULL && hashmapexpr != child )
10306	            {
10307	               SCIP_CALL( SCIPreplaceExprChild(scip, expr, SCIPexpriterGetChildIdxDFS(it), hashmapexpr) );
10308	            }
10309	         }
10310	         SCIPfreeExpriter(&it);
10311	      }
10312	   }
10313	
10314	   /* store variable expressions */
10315	   if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10316	   {
10317	      SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10318	   }
10319	
10320	   /* add manually locks to constraints that are not checked for feasibility */
10321	   if( !SCIPconsIsChecked(cons) )
10322	   {
10323	      assert(consdata->nlockspos == 0);
10324	      assert(consdata->nlocksneg == 0);
10325	
10326	      SCIP_CALL( addLocks(scip, cons, 1, 0) );
10327	   }
10328	
10329	   if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
10330	   {
10331	      SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10332	   }
10333	
10334	   /* TODO deal with infeasibility */
10335	   assert(!infeasible);
10336	
10337	   return SCIP_OKAY;
10338	}
10339	
10340	
10341	/** constraint deactivation notification method of constraint handler */
10342	static
10343	SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
10344	{  /*lint --e{715}*/
10345	   SCIP_CONSHDLRDATA* conshdlrdata;
10346	
10347	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10348	   assert(conshdlrdata != NULL);
10349	
10350	   if( SCIPgetStage(scip) < SCIP_STAGE_EXITSOLVE )
10351	   {
10352	      SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10353	   }
10354	
10355	   if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10356	   {
10357	      SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10358	      SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(cons)) );
10359	   }
10360	
10361	   /* remove locks that have been added in consActiveExpr() */
10362	   if( !SCIPconsIsChecked(cons) )
10363	   {
10364	      SCIP_CALL( addLocks(scip, cons, -1, 0) );
10365	
10366	      assert(SCIPconsGetData(cons)->nlockspos == 0);
10367	      assert(SCIPconsGetData(cons)->nlocksneg == 0);
10368	   }
10369	
10370	   return SCIP_OKAY;
10371	}
10372	
10373	
10374	/** constraint enabling notification method of constraint handler */
10375	static
10376	SCIP_DECL_CONSENABLE(consEnableNonlinear)
10377	{  /*lint --e{715}*/
10378	   SCIP_CONSHDLRDATA* conshdlrdata;
10379	
10380	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10381	   assert(conshdlrdata != NULL);
10382	
10383	   if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10384	   {
10385	      SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10386	   }
10387	
10388	   return SCIP_OKAY;
10389	}
10390	
10391	
10392	/** constraint disabling notification method of constraint handler */
10393	static
10394	SCIP_DECL_CONSDISABLE(consDisableNonlinear)
10395	{  /*lint --e{715}*/
10396	   SCIP_CONSHDLRDATA* conshdlrdata;
10397	
10398	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10399	   assert(conshdlrdata != NULL);
10400	
10401	   if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10402	   {
10403	      SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10404	   }
10405	
10406	   return SCIP_OKAY;
10407	}
10408	
10409	/** variable deletion of constraint handler */
10410	#ifdef SCIP_DISABLED_CODE
10411	static
10412	SCIP_DECL_CONSDELVARS(consDelvarsNonlinear)
10413	{  /*lint --e{715}*/
10414	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10415	   SCIPABORT(); /*lint --e{527}*/
10416	
10417	   return SCIP_OKAY;
10418	}
10419	#else
10420	#define consDelvarsNonlinear NULL
10421	#endif
10422	
10423	
10424	/** constraint display method of constraint handler */
10425	static
10426	SCIP_DECL_CONSPRINT(consPrintNonlinear)
10427	{  /*lint --e{715}*/
10428	   SCIP_CONSDATA* consdata;
10429	
10430	   consdata = SCIPconsGetData(cons);
10431	   assert(consdata != NULL);
10432	   assert(consdata->expr != NULL);
10433	
10434	   /* print left hand side for ranged constraints */
10435	   if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10436	   {
10437	      SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10438	   }
10439	
10440	   /* print expression */
10441	   SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
10442	
10443	   /* print right hand side */
10444	   if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10445	      SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
10446	   else if( !SCIPisInfinity(scip, consdata->rhs) )
10447	      SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
10448	   else if( !SCIPisInfinity(scip, -consdata->lhs) )
10449	      SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
10450	   else
10451	      SCIPinfoMessage(scip, file, " [free]");
10452	
10453	   return SCIP_OKAY;
10454	}
10455	
10456	
10457	/** constraint copying method of constraint handler */
10458	static
10459	SCIP_DECL_CONSCOPY(consCopyNonlinear)
10460	{  /*lint --e{715}*/
10461	   SCIP_CONSHDLR* targetconshdlr;
10462	   SCIP_EXPR* targetexpr = NULL;
10463	   SCIP_CONSDATA* sourcedata;
10464	
10465	   assert(cons != NULL);
10466	
10467	   sourcedata = SCIPconsGetData(sourcecons);
10468	   assert(sourcedata != NULL);
10469	
10470	   targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10471	   assert(targetconshdlr != NULL);
10472	
10473	   SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
10474	
10475	   if( targetexpr == NULL )
10476	      *valid = FALSE;
10477	
10478	   *cons = NULL;
10479	   if( *valid )
10480	   {
10481	      /* create copy (only capture targetexpr, no need to copy again) */
10482	      SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
10483	         targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
10484	         initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10485	   }
10486	
10487	   if( targetexpr != NULL )
10488	   {
10489	      /* release target expr */
10490	      SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
10491	   }
10492	
10493	   return SCIP_OKAY;
10494	}
10495	
10496	
10497	/** constraint parsing method of constraint handler */
10498	static
10499	SCIP_DECL_CONSPARSE(consParseNonlinear)
10500	{  /*lint --e{715}*/
10501	   SCIP_Real  lhs;
10502	   SCIP_Real  rhs;
10503	   const char* endptr;
10504	   SCIP_EXPR* consexprtree;
10505	
10506	   SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
10507	
10508	   assert(scip != NULL);
10509	   assert(success != NULL);
10510	   assert(str != NULL);
10511	   assert(name != NULL);
10512	   assert(cons != NULL);
10513	
10514	   *success = FALSE;
10515	
10516	   /* return if string empty */
10517	   if( !*str )
10518	      return SCIP_OKAY;
10519	
10520	   endptr = str;
10521	
10522	   /* set left and right hand side to their default values */
10523	   lhs = -SCIPinfinity(scip);
10524	   rhs =  SCIPinfinity(scip);
10525	
10526	   /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
10527	
10528	   /* check for left hand side */
10529	   if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
10530	   {
10531	      /* there is a number coming, maybe it is a left-hand-side */
10532	      if( !SCIPstrToRealValue(str, &lhs, (char**)&endptr) )
10533	      {
10534	         SCIPerrorMessage("error parsing number from <%s>\n", str);
10535	         return SCIP_READERROR;
10536	      }
10537	
10538	      /* ignore whitespace */
10539	      while( isspace((unsigned char)*endptr) )
10540	         ++endptr;
10541	
10542	      if( endptr[0] != '<' || endptr[1] != '=' )
10543	      {
10544	         /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
10545	         lhs = -SCIPinfinity(scip);
10546	      }
10547	      else
10548	      {
10549	         /* it was indeed a left-hand-side, so continue parsing after it */
10550	         str = endptr + 2;
10551	
10552	         /* ignore whitespace */
10553	         while( isspace((unsigned char)*str) )
10554	            ++str;
10555	      }
10556	   }
10557	
10558	   SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
10559	
10560	   /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
10561	   SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
10562	
10563	   /* check for left or right hand side */
10564	   while( isspace((unsigned char)*str) )
10565	      ++str;
10566	
10567	   /* check for free constraint */
10568	   if( strncmp(str, "[free]", 6) == 0 )
10569	   {
10570	      if( !SCIPisInfinity(scip, -lhs) )
10571	      {
10572	         SCIPerrorMessage("cannot have left hand side and [free] status \n");
10573	         SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10574	         return SCIP_OKAY;
10575	      }
10576	      *success = TRUE;
10577	   }
10578	   else
10579	   {
10580	      switch( *str )
10581	      {
10582	         case '<':
10583	            *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10584	            break;
10585	         case '=':
10586	            if( !SCIPisInfinity(scip, -lhs) )
10587	            {
10588	               SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
10589	               SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10590	               return SCIP_OKAY;
10591	            }
10592	            else
10593	            {
10594	               *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10595	               lhs = rhs;
10596	            }
10597	            break;
10598	         case '>':
10599	            if( !SCIPisInfinity(scip, -lhs) )
10600	            {
10601	               SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
10602	               SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10603	               return SCIP_OKAY;
10604	            }
10605	            else
10606	            {
10607	               *success = SCIPstrToRealValue(str+2, &lhs, (char**)&endptr);
10608	               break;
10609	            }
10610	         case '\0':
10611	            *success = TRUE;
10612	            break;
10613	         default:
10614	            SCIPerrorMessage("unexpected character %c\n", *str);
10615	            SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10616	            return SCIP_OKAY;
10617	      }
10618	   }
10619	
10620	   /* create constraint */
10621	   SCIP_CALL( createCons(scip, conshdlr, cons, name,
10622	      consexprtree, lhs, rhs, FALSE,
10623	      initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10624	   assert(*cons != NULL);
10625	
10626	   SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10627	
10628	   SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
10629	
10630	   return SCIP_OKAY;
10631	}
10632	
10633	
10634	/** constraint method of constraint handler which returns the variables (if possible) */
10635	static
10636	SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
10637	{  /*lint --e{715}*/
10638	   SCIP_CONSDATA* consdata;
10639	   int i;
10640	
10641	   consdata = SCIPconsGetData(cons);
10642	   assert(consdata != NULL);
10643	
10644	   /* store variable expressions if not done so far */
10645	   SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10646	
10647	   /* check whether array is too small in order to store all variables */
10648	   if( varssize < consdata->nvarexprs )
10649	   {
10650	      *success = FALSE;
10651	      return SCIP_OKAY;
10652	   }
10653	
10654	   for( i = 0; i < consdata->nvarexprs; ++i )
10655	   {
10656	      vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
10657	      assert(vars[i] != NULL);
10658	   }
10659	
10660	   *success = TRUE;
10661	
10662	   return SCIP_OKAY;
10663	}
10664	
10665	/** constraint method of constraint handler which returns the number of variables (if possible) */
10666	static
10667	SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
10668	{  /*lint --e{715}*/
10669	   SCIP_CONSDATA* consdata;
10670	
10671	   consdata = SCIPconsGetData(cons);
10672	   assert(consdata != NULL);
10673	
10674	   /* store variable expressions if not done so far */
10675	   SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10676	
10677	   *nvars = consdata->nvarexprs;
10678	   *success = TRUE;
10679	
10680	   return SCIP_OKAY;
10681	}
10682	
10683	/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
10684	#ifdef SCIP_DISABLED_CODE
10685	static
10686	SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsNonlinear)
10687	{  /*lint --e{715}*/
10688	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10689	   SCIPABORT(); /*lint --e{527}*/
10690	
10691	   return SCIP_OKAY;
10692	}
10693	#else
10694	#define consGetDiveBdChgsNonlinear NULL
10695	#endif
10696	
10697	/** output method of statistics table to output file stream 'file' */
10698	static
10699	SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
10700	{ /*lint --e{715}*/
10701	   SCIP_CONSHDLR* conshdlr;
10702	   SCIP_CONSHDLRDATA* conshdlrdata;
10703	
10704	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10705	   assert(conshdlr != NULL);
10706	
10707	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10708	   assert(conshdlrdata != NULL);
10709	
10710	   /* print statistics for constraint handler */
10711	   SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
10712	   SCIPinfoMessage(scip, file, "  enforce%-10s:", "");
10713	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
10714	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
10715	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
10716	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
10717	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
10718	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
10719	   SCIPinfoMessage(scip, file, "\n");
10720	   SCIPinfoMessage(scip, file, "  presolve%-9s: %-65s", "", "");
10721	   SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
10722	   SCIPinfoMessage(scip, file, "\n");
10723	
10724	   return SCIP_OKAY;
10725	}
10726	
10727	/** output method of statistics table to output file stream 'file' */
10728	static
10729	SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
10730	{ /*lint --e{715}*/
10731	   SCIP_CONSHDLR* conshdlr;
10732	   SCIP_CONSHDLRDATA* conshdlrdata;
10733	
10734	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10735	   assert(conshdlr != NULL);
10736	
10737	   /* skip nlhdlr table if there never were active nonlinear constraints */
10738	   if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
10739	      return SCIP_OKAY;
10740	
10741	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10742	   assert(conshdlrdata != NULL);
10743	
10744	   /* print statistics for nonlinear handlers */
10745	   SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
10746	
10747	   return SCIP_OKAY;
10748	}
10749	
10750	/** execution method of display nlhdlrs dialog */
10751	static
10752	SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
10753	{  /*lint --e{715}*/
10754	   SCIP_CONSHDLR* conshdlr;
10755	   SCIP_CONSHDLRDATA* conshdlrdata;
10756	   int i;
10757	
10758	   /* add dialog to history of dialogs that have been executed */
10759	   SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
10760	
10761	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10762	   assert(conshdlr != NULL);
10763	
10764	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10765	   assert(conshdlrdata != NULL);
10766	
10767	   /* display list of nonlinear handler */
10768	   SCIPdialogMessage(scip, NULL, "\n");
10769	   SCIPdialogMessage(scip, NULL, " nonlinear handler  enabled  detectprio  enforceprio  description\n");
10770	   SCIPdialogMessage(scip, NULL, " -----------------  -------  ----------  -----------  -----------\n");
10771	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10772	   {
10773	      SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
10774	      assert(nlhdlr != NULL);
10775	
10776	      SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
10777	      SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
10778	      SCIPdialogMessage(scip, NULL, " %10d ", SCIPnlhdlrGetDetectPriority(nlhdlr));
10779	      SCIPdialogMessage(scip, NULL, " %11d ", SCIPnlhdlrGetEnfoPriority(nlhdlr));
10780	      SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
10781	      SCIPdialogMessage(scip, NULL, "\n");
10782	   }
10783	   SCIPdialogMessage(scip, NULL, "\n");
10784	
10785	   /* next dialog will be root dialog again */
10786	   *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
10787	
10788	   return SCIP_OKAY;
10789	}
10790	
10791	/*
10792	 * constraint handler specific interface methods
10793	 */
10794	
10795	/** creates the handler for nonlinear constraints and includes it in SCIP */
10796	SCIP_RETCODE SCIPincludeConshdlrNonlinear(
10797	   SCIP*                 scip                /**< SCIP data structure */
10798	   )
10799	{
10800	   SCIP_CONSHDLRDATA* conshdlrdata;
10801	   SCIP_DIALOG* parentdialog;
10802	
10803	   /* create nonlinear constraint handler data */
10804	   SCIP_CALL( SCIPallocClearMemory(scip, &conshdlrdata) );
10805	   conshdlrdata->intevalvar = intEvalVarBoundTightening;
10806	   conshdlrdata->curboundstag = 1;
10807	   conshdlrdata->lastboundrelax = 1;
10808	   conshdlrdata->curpropboundstag = 1;
10809	   conshdlrdata->newsoleventfilterpos = -1;
10810	   SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
10811	   SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
10812	   SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
10813	
10814	   /* include constraint handler */
10815	   SCIP_CALL( SCIPincludeConshdlr(scip, CONSHDLR_NAME, CONSHDLR_DESC,
10816	         CONSHDLR_SEPAPRIORITY, CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY,
10817	         CONSHDLR_SEPAFREQ, CONSHDLR_PROPFREQ, CONSHDLR_EAGERFREQ, CONSHDLR_MAXPREROUNDS,
10818	         CONSHDLR_DELAYSEPA, CONSHDLR_DELAYPROP, CONSHDLR_NEEDSCONS,
10819	         CONSHDLR_PROP_TIMING, CONSHDLR_PRESOLTIMING,
10820	         conshdlrCopyNonlinear,
10821	         consFreeNonlinear, consInitNonlinear, consExitNonlinear,
10822	         consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
10823	         consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
10824	         consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
10825	         consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
10826	         consActiveNonlinear, consDeactiveNonlinear,
10827	         consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
10828	         consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
10829	         consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, conshdlrdata) );
10830	
10831	   /* add nonlinear constraint handler parameters */
10832	   /* TODO organize into more subcategories */
10833	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
10834	         "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
10835	         &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
10836	
10837	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
10838	         "whether to check bounds of all auxiliary variable to seed reverse propagation",
10839	         &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
10840	
10841	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
10842	         "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",
10843	         &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
10844	
10845	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
10846	         "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
10847	         &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10848	
10849	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
10850	         "by how much to relax constraint sides during bound tightening",
10851	         &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10852	
10853	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
10854	         "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
10855	         &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
10856	
10857	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
10858	         "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
10859	         &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
10860	
10861	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
10862	         "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
10863	         &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
10864	
10865	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
10866	           "maximal number of auxiliary expressions per bilinear term",
10867	           &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
10868	
10869	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
10870	         "whether to reformulate products of binary variables during presolving",
10871	         &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
10872	
10873	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
10874	         "whether to use the AND constraint handler for reformulating binary products",
10875	         &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
10876	
10877	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
10878	         "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
10879	         &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
10880	
10881	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
10882	         "whether to forbid multiaggregation of nonlinear variables",
10883	         &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
10884	
10885	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
10886	         "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
10887	         &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
10888	
10889	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
10890	         "whether to (re)run propagation in enforcement",
10891	         &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
10892	
10893	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
10894	         "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
10895	         &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
10896	
10897	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
10898	         "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
10899	         &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
10900	
10901	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
10902	         "consider efficacy requirement when deciding whether a cut is \"strong\"",
10903	         &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
10904	
10905	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
10906	         "whether to force \"strong\" cuts in enforcement",
10907	         &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
10908	
10909	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
10910	         "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
10911	         &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
10912	
10913	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
10914	         "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
10915	         &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
10916	
10917	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
10918	         "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",
10919	         &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
10920	
10921	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
10922	         "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
10923	         &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
10924	
10925	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
10926	         "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)",
10927	         &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
10928	
10929	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
10930	         "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
10931	         &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
10932	
10933	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
10934	         "whether to use external branching candidates and branching rules for branching",
10935	         &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
10936	
10937	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
10938	         "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
10939	         &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
10940	
10941	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
10942	         "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
10943	         &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
10944	
10945	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
10946	         "weight by how much to consider the violation assigned to a variable for its branching score",
10947	         &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10948	
10949	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
10950	         "weight by how much to consider the dual values of rows that contain a variable for its branching score",
10951	         &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10952	
10953	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
10954	         "weight by how much to consider the pseudo cost of a variable for its branching score",
10955	         &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10956	
10957	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
10958	         "weight by how much to consider the domain width in branching score",
10959	         &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10960	
10961	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
10962	         "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
10963	         &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
10964	
10965	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
10966	         "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
10967	         &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
10968	
10969	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
10970	         "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
10971	         &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
10972	
10973	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
10974	         "minimum pseudo-cost update count required to consider pseudo-costs reliable",
10975	         &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10976	
10977	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
10978	         "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)",
10979	         &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
10980	
10981	   /* include handler for bound change events */
10982	   SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
10983	         "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
10984	   assert(conshdlrdata->eventhdlr != NULL);
10985	
10986	   /* include tables for statistics */
10987	   assert(SCIPfindTable(scip, TABLE_NAME_NONLINEAR) == NULL);
10988	   SCIP_CALL( SCIPincludeTable(scip, TABLE_NAME_NONLINEAR, TABLE_DESC_NONLINEAR, FALSE,
10989	         NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
10990	         NULL, TABLE_POSITION_NONLINEAR, TABLE_EARLIEST_STAGE_NONLINEAR) );
10991	
10992	   assert(SCIPfindTable(scip, TABLE_NAME_NLHDLR) == NULL);
10993	   SCIP_CALL( SCIPincludeTable(scip, TABLE_NAME_NLHDLR, TABLE_DESC_NLHDLR, TRUE,
10994	         NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
10995	         NULL, TABLE_POSITION_NLHDLR, TABLE_EARLIEST_STAGE_NLHDLR) );
10996	
10997	   /* create, include, and release display nlhdlrs dialog */
10998	   if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
10999	   {
11000	      SCIP_DIALOG* dialog;
11001	
11002	      assert(parentdialog != NULL);
11003	      assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
11004	
11005	      SCIP_CALL( SCIPincludeDialog(scip, &dialog,
11006	            NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
11007	            DIALOG_NAME, DIALOG_DESC, DIALOG_ISSUBMENU, NULL) );
11008	      SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
11009	      SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
11010	   }
11011	
11012	   SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
11013	         processNewSolutionEvent, NULL) );
11014	
11015	   return SCIP_OKAY;
11016	}
11017	
11018	/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
11019	SCIP_RETCODE SCIPincludeConsUpgradeNonlinear(
11020	   SCIP*                 scip,               /**< SCIP data structure */
11021	   SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)),  /**< method to call for upgrading nonlinear constraint */
11022	   int                   priority,           /**< priority of upgrading method */
11023	   SCIP_Bool             active,             /**< should the upgrading method by active by default? */
11024	   const char*           conshdlrname        /**< name of the constraint handler */
11025	   )
11026	{
11027	   SCIP_CONSHDLR*     conshdlr;
11028	   SCIP_CONSHDLRDATA* conshdlrdata;
11029	   CONSUPGRADE*       consupgrade;
11030	   char               paramname[SCIP_MAXSTRLEN];
11031	   char               paramdesc[SCIP_MAXSTRLEN];
11032	   int                i;
11033	
11034	   assert(conshdlrname != NULL );
11035	   assert(nlconsupgd != NULL);
11036	
11037	   /* find the nonlinear constraint handler */
11038	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11039	   if( conshdlr == NULL )
11040	   {
11041	      SCIPerrorMessage("nonlinear constraint handler not found\n");
11042	      return SCIP_PLUGINNOTFOUND;
11043	   }
11044	
11045	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11046	   assert(conshdlrdata != NULL);
11047	
11048	   /* check whether upgrade method exists already */
11049	   for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
11050	   {
11051	      if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
11052	      {
11053	#ifdef SCIP_DEBUG
11054	         SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
11055	#endif
11056	         return SCIP_OKAY;
11057	      }
11058	   }
11059	
11060	   /* create a nonlinear constraint upgrade data object */
11061	   SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
11062	   consupgrade->consupgd = nlconsupgd;
11063	   consupgrade->priority = priority;
11064	   consupgrade->active   = active;
11065	
11066	   /* insert nonlinear constraint upgrade method into constraint handler data */
11067	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
11068	   assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
11069	
11070	   for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
11071	      conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
11072	   assert(0 <= i && i <= conshdlrdata->nconsupgrades);
11073	   conshdlrdata->consupgrades[i] = consupgrade;
11074	   conshdlrdata->nconsupgrades++;
11075	
11076	   /* adds parameter to turn on and off the upgrading step */
11077	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
11078	   (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
11079	   SCIP_CALL( SCIPaddBoolParam(scip,
11080	         paramname, paramdesc,
11081	         &consupgrade->active, FALSE, active, NULL, NULL) );
11082	
11083	   return SCIP_OKAY;
11084	}
11085	
11086	/** creates and captures a nonlinear constraint
11087	 *
11088	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11089	 */
11090	SCIP_RETCODE SCIPcreateConsNonlinear(
11091	   SCIP*                 scip,               /**< SCIP data structure */
11092	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11093	   const char*           name,               /**< name of constraint */
11094	   SCIP_EXPR*            expr,               /**< expression of constraint (must not be NULL) */
11095	   SCIP_Real             lhs,                /**< left hand side of constraint */
11096	   SCIP_Real             rhs,                /**< right hand side of constraint */
11097	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
11098	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11099	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
11100	                                              *   Usually set to TRUE. */
11101	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
11102	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11103	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
11104	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11105	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
11106	                                              *   Usually set to TRUE. */
11107	   SCIP_Bool             local,              /**< is constraint only valid locally?
11108	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11109	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
11110	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
11111	                                              *   adds coefficients to this constraint. */
11112	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
11113	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
11114	                                              *   are separated as constraints. */
11115	   SCIP_Bool             removable           /**< should the relaxation be removed from the LP due to aging or cleanup?
11116	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11117	   )
11118	{
11119	   /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
11120	   SCIP_CONSHDLR* conshdlr;
11121	
11122	   /* find the nonlinear constraint handler */
11123	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11124	   if( conshdlr == NULL )
11125	   {
11126	      SCIPerrorMessage("nonlinear constraint handler not found\n");
11127	      return SCIP_PLUGINNOTFOUND;
11128	   }
11129	
11130	   /* create constraint */
11131	   SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
11132	      initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11133	
11134	   return SCIP_OKAY;
11135	}
11136	
11137	/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
11138	 *
11139	 *  All flags can be set via SCIPconsSetFLAGNAME-methods.
11140	 *
11141	 *  @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
11142	 *
11143	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11144	 */
11145	SCIP_RETCODE SCIPcreateConsBasicNonlinear(
11146	   SCIP*                 scip,               /**< SCIP data structure */
11147	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11148	   const char*           name,               /**< name of constraint */
11149	   SCIP_EXPR*            expr,               /**< expression of constraint (must not be NULL) */
11150	   SCIP_Real             lhs,                /**< left hand side of constraint */
11151	   SCIP_Real             rhs                 /**< right hand side of constraint */
11152	   )
11153	{
11154	   SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
11155	         TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11156	
11157	   return SCIP_OKAY;
11158	}
11159	
11160	/** creates and captures a quadratic nonlinear constraint
11161	 *
11162	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11163	 */
11164	SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(
11165	   SCIP*                 scip,               /**< SCIP data structure */
11166	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11167	   const char*           name,               /**< name of constraint */
11168	   int                   nlinvars,           /**< number of linear terms */
11169	   SCIP_VAR**            linvars,            /**< array with variables in linear part */
11170	   SCIP_Real*            lincoefs,           /**< array with coefficients of variables in linear part */
11171	   int                   nquadterms,         /**< number of quadratic terms */
11172	   SCIP_VAR**            quadvars1,          /**< array with first variables in quadratic terms */
11173	   SCIP_VAR**            quadvars2,          /**< array with second variables in quadratic terms */
11174	   SCIP_Real*            quadcoefs,          /**< array with coefficients of quadratic terms */
11175	   SCIP_Real             lhs,                /**< left hand side of quadratic equation */
11176	   SCIP_Real             rhs,                /**< right hand side of quadratic equation */
11177	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
11178	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11179	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
11180	                                              *   Usually set to TRUE. */
11181	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
11182	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11183	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
11184	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11185	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
11186	                                              *   Usually set to TRUE. */
11187	   SCIP_Bool             local,              /**< is constraint only valid locally?
11188	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11189	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
11190	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
11191	                                              *   adds coefficients to this constraint. */
11192	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
11193	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
11194	                                              *   are separated as constraints. */
11195	   SCIP_Bool             removable           /**< should the relaxation be removed from the LP due to aging or cleanup?
11196	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11197	   )
11198	{
11199	   SCIP_CONSHDLR* conshdlr;
11200	   SCIP_EXPR* expr;
11201	
11202	   assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
11203	   assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
11204	
11205	   /* get nonlinear constraint handler */
11206	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11207	   if( conshdlr == NULL )
11208	   {
11209	      SCIPerrorMessage("nonlinear constraint handler not found\n");
11210	      return SCIP_PLUGINNOTFOUND;
11211	   }
11212	
11213	   /* create quadratic expression */
11214	   SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
11215	   assert(expr != NULL);
11216	
11217	   /* create nonlinear constraint */
11218	   SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
11219	      initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11220	
11221	   /* release quadratic expression (captured by constraint now) */
11222	   SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11223	
11224	   return SCIP_OKAY;
11225	}
11226	
11227	/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
11228	 *
11229	 *  All flags can be set via SCIPconsSetFLAGNAME-methods.
11230	 *
11231	 *  @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
11232	 *
11233	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11234	 */
11235	SCIP_RETCODE SCIPcreateConsBasicQuadraticNonlinear(
11236	   SCIP*                 scip,               /**< SCIP data structure */
11237	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11238	   const char*           name,               /**< name of constraint */
11239	   int                   nlinvars,           /**< number of linear terms */
11240	   SCIP_VAR**            linvars,            /**< array with variables in linear part */
11241	   SCIP_Real*            lincoefs,           /**< array with coefficients of variables in linear part */
11242	   int                   nquadterms,         /**< number of quadratic terms */
11243	   SCIP_VAR**            quadvars1,          /**< array with first variables in quadratic terms */
11244	   SCIP_VAR**            quadvars2,          /**< array with second variables in quadratic terms */
11245	   SCIP_Real*            quadcoefs,          /**< array with coefficients of quadratic terms */
11246	   SCIP_Real             lhs,                /**< left hand side of quadratic equation */
11247	   SCIP_Real             rhs                 /**< right hand side of quadratic equation */
11248	   )
11249	{
11250	   SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11251	      TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11252	
11253	   return SCIP_OKAY;
11254	}
11255	
11256	/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
11257	 *
11258	 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
11259	 *
11260	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11261	 */
11262	SCIP_RETCODE SCIPcreateConsBasicSignpowerNonlinear(
11263	   SCIP*                 scip,               /**< SCIP data structure */
11264	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11265	   const char*           name,               /**< name of constraint */
11266	   SCIP_VAR*             x,                  /**< nonlinear variable x in constraint */
11267	   SCIP_VAR*             z,                  /**< linear variable z in constraint */
11268	   SCIP_Real             exponent,           /**< exponent n of |x+offset|^n term in constraint */
11269	   SCIP_Real             xoffset,            /**< offset in |x+offset|^n term in constraint */
11270	   SCIP_Real             zcoef,              /**< coefficient of z in constraint */
11271	   SCIP_Real             lhs,                /**< left hand side of constraint */
11272	   SCIP_Real             rhs                 /**< right hand side of constraint */
11273	   )
11274	{
11275	   SCIP_EXPR* xexpr;
11276	   SCIP_EXPR* terms[2];
11277	   SCIP_Real coefs[2];
11278	   SCIP_EXPR* sumexpr;
11279	
11280	   assert(x != NULL);
11281	   assert(z != NULL);
11282	
11283	   SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
11284	   if( xoffset != 0.0 )
11285	   {
11286	      SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
11287	      SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
11288	
11289	      SCIP_CALL( SCIPreleaseExpr(scip,  &sumexpr) );
11290	   }
11291	   else
11292	   {
11293	      SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) );  /* signpow(x, exponent) */
11294	   }
11295	   coefs[0] = 1.0;
11296	
11297	   SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
11298	   coefs[1] = zcoef;
11299	
11300	   SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) );  /* signpowexpr + zcoef * z */
11301	
11302	   SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
11303	
11304	   SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11305	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11306	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11307	   SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
11308	
11309	   return SCIP_OKAY;
11310	}
11311	
11312	/** gets tag indicating current local variable bounds */
11313	SCIP_Longint SCIPgetCurBoundsTagNonlinear(
11314	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11315	   )
11316	{
11317	   SCIP_CONSHDLRDATA* conshdlrdata;
11318	
11319	   assert(conshdlr != NULL);
11320	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11321	
11322	   return conshdlrdata->curboundstag;
11323	}
11324	
11325	/** gets the `curboundstag` from the last time where variable bounds were relaxed */
11326	SCIP_Longint SCIPgetLastBoundRelaxTagNonlinear(
11327	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11328	   )
11329	{
11330	   SCIP_CONSHDLRDATA* conshdlrdata;
11331	
11332	   assert(conshdlr != NULL);
11333	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11334	
11335	   return conshdlrdata->lastboundrelax;
11336	}
11337	
11338	/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
11339	 *
11340	 * @attention This method is not intended for normal use.
11341	 *   These tags are maintained by the event handler for variable bound change events.
11342	 *   This method is used by some unittests.
11343	 */
11344	void SCIPincrementCurBoundsTagNonlinear(
11345	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
11346	   SCIP_Bool             boundrelax          /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
11347	   )
11348	{
11349	   SCIP_CONSHDLRDATA* conshdlrdata;
11350	
11351	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11352	   assert(conshdlrdata != NULL);
11353	
11354	   ++conshdlrdata->curboundstag;
11355	   assert(conshdlrdata->curboundstag > 0);
11356	
11357	   if( boundrelax )
11358	      conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
11359	}
11360	
11361	/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
11362	SCIP_HASHMAP* SCIPgetVarExprHashmapNonlinear(
11363	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11364	   )
11365	{
11366	   assert(conshdlr != NULL);
11367	
11368	   return SCIPconshdlrGetData(conshdlr)->var2expr;
11369	}
11370	
11371	/** processes a rowprep for cut addition and maybe report branchscores */
11372	SCIP_RETCODE SCIPprocessRowprepNonlinear(
11373	   SCIP*                 scip,               /**< SCIP data structure */
11374	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler which provided the estimator */
11375	   SCIP_CONS*            cons,               /**< nonlinear constraint */
11376	   SCIP_EXPR*            expr,               /**< expression */
11377	   SCIP_ROWPREP*         rowprep,            /**< cut to be added */
11378	   SCIP_Bool             overestimate,       /**< whether the expression needs to be over- or underestimated */
11379	   SCIP_VAR*             auxvar,             /**< auxiliary variable */
11380	   SCIP_Real             auxvalue,           /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
11381	   SCIP_Bool             allowweakcuts,      /**< whether we should only look for "strong" cuts, or anything that separates is fine */
11382	   SCIP_Bool             branchscoresuccess, /**< whether the estimator generation generated branching scores */
11383	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement, or only in separation */
11384	   SCIP_SOL*             sol,                /**< solution to be separated (NULL for the LP solution) */
11385	   SCIP_RESULT*          result              /**< pointer to store the result */
11386	   )
11387	{
11388	   SCIP_Real cutviol;
11389	   SCIP_CONSHDLRDATA* conshdlrdata;
11390	   SCIP_Real auxvarvalue = SCIP_INVALID;
11391	   SCIP_Bool sepasuccess;
11392	   SCIP_Real estimateval = SCIP_INVALID;
11393	   SCIP_Real mincutviolation;
11394	
11395	   assert(nlhdlr != NULL);
11396	   assert(cons != NULL);
11397	   assert(expr != NULL);
11398	   assert(rowprep != NULL);
11399	   assert(auxvar != NULL);
11400	   assert(result != NULL);
11401	
11402	   /* decide on minimal violation of cut */
11403	   if( sol == NULL )
11404	      mincutviolation = SCIPgetLPFeastol(scip);  /* we enforce an LP solution */
11405	   else
11406	      mincutviolation = SCIPfeastol(scip);
11407	
11408	   conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11409	   assert(conshdlrdata != NULL);
11410	
11411	   sepasuccess = TRUE;
11412	
11413	   cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
11414	   if( cutviol > 0.0 )
11415	   {
11416	      auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
11417	
11418	      /* check whether cut is weak (if f(x) not defined, then it's never weak) */
11419	      if( !allowweakcuts && auxvalue != SCIP_INVALID )
11420	      {
11421	         /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
11422	          * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
11423	          * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
11424	          * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
11425	          * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
11426	          *   <->   c'x-b - z <= weakcutthreshold * (f(x)-z)
11427	          *
11428	          * if we are overestimating, we have z >= c'x-b >= f(x)
11429	          * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
11430	          * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
11431	          *   <->   c'x-b - z >= weakcutthreshold * (f(x)-z)
11432	          *
11433	          * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
11434	          */
11435	         if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11436	             ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11437	         {
11438	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s succeeded, but cut is too "\
11439	                           "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11440	                                     SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11441	                                     auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
11442	            sepasuccess = FALSE;
11443	         }
11444	      }
11445	
11446	      /* save estimator value for later, see long comment above why this gives the value for c'x-b */
11447	      estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
11448	   }
11449	   else
11450	   {
11451	      sepasuccess = FALSE;
11452	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s succeeded, but cut does not "\
11453	                     "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
11454	   }
11455	
11456	   /* clean up estimator */
11457	   if( sepasuccess )
11458	   {
11459	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s succeeded: auxvarvalue %g "\
11460	                     "estimateval %g auxvalue %g (over %d)\n    ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11461	                               auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
11462	                       SCIPprintRowprep(scip, rowprep, enfologfile); )
11463	
11464	      /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
11465	       * instead, may even scale them down, that is, scale so that max coef is close to 1
11466	       */
11467	      if( !allowweakcuts )
11468	      {
11469	         SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
11470	
11471	         if( !sepasuccess )
11472	         {
11473	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cleanup cut failed due to bad numerics\n"); )
11474	         }
11475	         else
11476	         {
11477	            cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
11478	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cleanup succeeded, violation = %g and %sreliable, "\
11479	                           "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
11480	            if( sepasuccess )
11481	               sepasuccess = cutviol > mincutviolation;
11482	         }
11483	
11484	         if( sepasuccess && auxvalue != SCIP_INVALID )
11485	         {
11486	            /* check whether cut is weak now
11487	             * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
11488	             * reconstructing estimateval from cutviol (TODO improve or remove?)
11489	             */
11490	            SCIP_Real auxvarcoef = 0.0;
11491	            int i;
11492	
11493	            /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
11494	             * it should be...
11495	             */
11496	            for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
11497	            {
11498	               if( SCIProwprepGetVars(rowprep)[i] == auxvar )
11499	               {
11500	                  auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
11501	                  break;
11502	               }
11503	            }
11504	
11505	            if( auxvarcoef == 0.0 ||
11506	                (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11507	                ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11508	            {
11509	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11510	                  auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
11511	               sepasuccess = FALSE;
11512	            }
11513	         }
11514	      }
11515	      else
11516	      {
11517	         /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
11518	
11519	         /* if estimate didn't report branchscores explicitly, then consider branching on those children for
11520	          * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
11521	          */
11522	         if( !branchscoresuccess )
11523	            SCIProwprepRecordModifications(rowprep);
11524	
11525	         SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
11526	
11527	         if( !sepasuccess )
11528	         {
11529	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cleanup failed, %d coefs modified, cutviol %g\n",
11530	                                     SCIProwprepGetNModifiedVars(rowprep), cutviol); )
11531	         }
11532	
11533	         /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
11534	          * changed
11535	          */
11536	         if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
11537	         {
11538	            SCIP_Real violscore;
11539	
11540	#ifdef BRSCORE_ABSVIOL
11541	            violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
11542	#else
11543	            SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
11544	#endif
11545	            SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
11546	
11547	            /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
11548	             * - were fixed,
11549	             * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
11550	             * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
11551	             * the first case came up again in #3085 and I don't see how to exclude this in the assert,
11552	             * so I'm disabling the assert for now
11553	             */
11554	            /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
11555	                  strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
11556	         }
11557	      }
11558	   }
11559	
11560	   /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
11561	   if( sepasuccess )
11562	   {
11563	      SCIP_ROW* row;
11564	
11565	      if( conshdlrdata->branchdualweight > 0.0 )
11566	      {
11567	         /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
11568	          * skip if gap is zero
11569	          */
11570	         if( auxvalue == SCIP_INVALID )
11571	            strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
11572	         else if( !SCIPisEQ(scip, auxvalue, estimateval) )
11573	         {
11574	            char gap[40];
11575	            (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
11576	            strcat(SCIProwprepGetName(rowprep), gap);
11577	         }
11578	      }
11579	
11580	      SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
11581	
11582	      if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
11583	      {
11584	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cut efficacy %g is too low (minefficacy=%g)\n",
11585	                                  SCIPgetCutEfficacy(scip, sol, row), SCIPgetSepaMinEfficacy(scip)); )
11586	      }
11587	      else
11588	      {
11589	         SCIP_Bool infeasible;
11590	
11591	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    adding cut ");
11592	           SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
11593	
11594	         /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
11595	          * if we haven't found strong cuts before)
11596	          */
11597	         SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
11598	
11599	         /* mark row as not removable from LP for current node (this can prevent some cycling) */
11600	         if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
11601	            SCIPmarkRowNotRemovableLocal(scip, row);
11602	
11603	         if( infeasible )
11604	         {
11605	            *result = SCIP_CUTOFF;
11606	            SCIPnlhdlrIncrementNCutoffs(nlhdlr);
11607	         }
11608	         else
11609	         {
11610	            *result = SCIP_SEPARATED;
11611	            SCIPnlhdlrIncrementNSeparated(nlhdlr);
11612	         }
11613	      }
11614	
11615	      SCIP_CALL( SCIPreleaseRow(scip, &row) );
11616	   }
11617	   else if( branchscoresuccess )
11618	   {
11619	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    separation with estimate of nlhdlr %s failed, but "\
11620	                     "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
11621	
11622	      /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
11623	       * expressions eligible for branching candidate, see enforceConstraints() and branching()
11624	       */
11625	      *result = SCIP_BRANCHED;
11626	   }
11627	   else
11628	   {
11629	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    separation with estimate of nlhdlr %s failed and no "\
11630	                     "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
11631	                                                                                    " (!)" : ""); )
11632	   }
11633	
11634	   return SCIP_OKAY;
11635	}
11636	
11637	/** collects all bilinear terms for a given set of constraints
11638	 *
11639	 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
11640	 *       SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
11641	 */
11642	SCIP_RETCODE SCIPcollectBilinTermsNonlinear(
11643	   SCIP*                 scip,               /**< SCIP data structure */
11644	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
11645	   SCIP_CONS**           conss,              /**< nonlinear constraints */
11646	   int                   nconss              /**< total number of nonlinear constraints */
11647	   )
11648	{
11649	   assert(conshdlr != NULL);
11650	   assert(conss != NULL || nconss == 0);
11651	
11652	   SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11653	
11654	   return SCIP_OKAY;
11655	}
11656	
11657	/** returns the total number of bilinear terms that are contained in all nonlinear constraints
11658	 *
11659	 *  @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11660	 */
11661	int SCIPgetNBilinTermsNonlinear(
11662	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11663	   )
11664	{
11665	   SCIP_CONSHDLRDATA* conshdlrdata;
11666	
11667	   assert(conshdlr != NULL);
11668	
11669	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11670	   assert(conshdlrdata != NULL);
11671	
11672	   return conshdlrdata->nbilinterms;
11673	}
11674	
11675	/** returns all bilinear terms that are contained in all nonlinear constraints
11676	 *
11677	 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11678	 * @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.
11679	 */
11680	SCIP_CONSNONLINEAR_BILINTERM* SCIPgetBilinTermsNonlinear(
11681	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
11682	   )
11683	{
11684	   SCIP_CONSHDLRDATA* conshdlrdata;
11685	
11686	   assert(conshdlr != NULL);
11687	
11688	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11689	   assert(conshdlrdata != NULL);
11690	
11691	   return conshdlrdata->bilinterms;
11692	}
11693	
11694	/** returns the index of the bilinear term representing the product of the two given variables
11695	 *
11696	 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11697	 * @return The method returns -1 if the variables do not appear bilinearly.
11698	 */
11699	int SCIPgetBilinTermIdxNonlinear(
11700	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
11701	   SCIP_VAR*             x,                  /**< first variable */
11702	   SCIP_VAR*             y                   /**< second variable */
11703	   )
11704	{
11705	   SCIP_CONSHDLRDATA* conshdlrdata;
11706	   SCIP_CONSNONLINEAR_BILINTERM entry;
11707	   int idx;
11708	
11709	   assert(conshdlr != NULL);
11710	   assert(x != NULL);
11711	   assert(y != NULL);
11712	
11713	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11714	   assert(conshdlrdata != NULL);
11715	
11716	   if( conshdlrdata->bilinhashtable == NULL )
11717	   {
11718	      return -1;
11719	   }
11720	
11721	   /* ensure that x.index <= y.index */
11722	   if( SCIPvarCompare(x, y) == 1 )
11723	   {
11724	      SCIPswapPointers((void**)&x, (void**)&y);
11725	   }
11726	   assert(SCIPvarCompare(x, y) < 1);
11727	
11728	   /* use a new entry to find the image in the bilinear hash table */
11729	   entry.x = x;
11730	   entry.y = y;
11731	   idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
11732	   assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11733	   assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
11734	   assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
11735	
11736	   return idx;
11737	}
11738	
11739	/** returns the bilinear term that represents the product of two given variables
11740	 *
11741	 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11742	 * @return The method returns NULL if the variables do not appear bilinearly.
11743	 */
11744	SCIP_CONSNONLINEAR_BILINTERM* SCIPgetBilinTermNonlinear(
11745	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
11746	   SCIP_VAR*             x,                  /**< first variable */
11747	   SCIP_VAR*             y                   /**< second variable */
11748	   )
11749	{
11750	   SCIP_CONSHDLRDATA* conshdlrdata;
11751	   int idx;
11752	
11753	   assert(conshdlr != NULL);
11754	   assert(x != NULL);
11755	   assert(y != NULL);
11756	
11757	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11758	   assert(conshdlrdata != NULL);
11759	
11760	   idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
11761	   assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11762	
11763	   if( idx >= 0 )
11764	   {
11765	      return &conshdlrdata->bilinterms[idx];
11766	   }
11767	
11768	   return NULL;
11769	}
11770	
11771	/** evaluates an auxiliary expression for a bilinear term */
11772	SCIP_Real SCIPevalBilinAuxExprNonlinear(
11773	   SCIP*                 scip,               /**< SCIP data structure */
11774	   SCIP_VAR*             x,                  /**< first variable of the bilinear term */
11775	   SCIP_VAR*             y,                  /**< second variable of the bilinear term */
11776	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr,      /**< auxiliary expression */
11777	   SCIP_SOL*             sol                 /**< solution at which to evaluate (can be NULL) */
11778	   )
11779	{
11780	   assert(scip != NULL);
11781	   assert(x != NULL);
11782	   assert(y != NULL);
11783	   assert(auxexpr != NULL);
11784	   assert(auxexpr->auxvar != NULL);
11785	
11786	   return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
11787	          auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
11788	}
11789	
11790	/** stores the variables of a bilinear term in the data of the constraint handler */
11791	SCIP_RETCODE SCIPinsertBilinearTermExistingNonlinear(
11792	   SCIP*                 scip,               /**< SCIP data structure */
11793	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
11794	   SCIP_VAR*             x,                  /**< first variable */
11795	   SCIP_VAR*             y,                  /**< second variable */
11796	   SCIP_VAR*             auxvar,             /**< auxiliary variable (might be NULL) */
11797	   int                   nlockspos,          /**< number of positive expression locks */
11798	   int                   nlocksneg           /**< number of negative expression locks */
11799	   )
11800	{
11801	   SCIP_CONSHDLRDATA* conshdlrdata;
11802	   SCIP_CONSNONLINEAR_BILINTERM* term;
11803	   int idx;
11804	
11805	   assert(conshdlr != NULL);
11806	
11807	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11808	   assert(conshdlrdata != NULL);
11809	
11810	   SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
11811	
11812	   term = &conshdlrdata->bilinterms[idx];
11813	   assert(term != NULL);
11814	   assert(term->nauxexprs == 0);  /* existing terms should be added before implicit terms */
11815	   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) */
11816	
11817	   /* store and capture auxiliary variable */
11818	   if( auxvar != NULL )
11819	   {
11820	      term->aux.var = auxvar;
11821	      SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
11822	   }
11823	
11824	   return SCIP_OKAY;
11825	}
11826	
11827	/** stores the variables of a bilinear term in the data of the constraint handler */
11828	SCIP_RETCODE SCIPinsertBilinearTermImplicitNonlinear(
11829	   SCIP*                 scip,               /**< SCIP data structure */
11830	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
11831	   SCIP_VAR*             x,                  /**< first variable */
11832	   SCIP_VAR*             y,                  /**< second variable */
11833	   SCIP_VAR*             auxvar,             /**< auxiliary variable (might be NULL) */
11834	   SCIP_Real             coefx,              /**< coefficient of x in the auxiliary expression */
11835	   SCIP_Real             coefy,              /**< coefficient of y in the auxiliary expression */
11836	   SCIP_Real             coefaux,            /**< coefficient of auxvar in the auxiliary expression */
11837	   SCIP_Real             cst,                /**< constant of the auxiliary expression */
11838	   SCIP_Bool             overestimate        /**< whether the auxiliary expression overestimates the bilinear product */
11839	   )
11840	{
11841	   SCIP_CONSHDLRDATA* conshdlrdata;
11842	   SCIP_CONSNONLINEAR_BILINTERM* term;
11843	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr;
11844	   int idx;
11845	   int nlockspos;
11846	   int nlocksneg;
11847	   SCIP_Bool added;
11848	
11849	   assert(conshdlr != NULL);
11850	
11851	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11852	   assert(conshdlrdata != NULL);
11853	
11854	   nlockspos = overestimate ? 1 : 0;
11855	   nlocksneg = overestimate ? 0 : 1;
11856	
11857	   SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
11858	
11859	   term = &conshdlrdata->bilinterms[idx];
11860	   assert(term != NULL);
11861	   assert(SCIPvarCompare(term->x, term->y) < 1);
11862	
11863	   if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
11864	   {
11865	      SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
11866	      /* this is the case where we are adding an implicitly defined relation for a product that has already
11867	       * been explicitly defined; convert auxvar into an auxexpr */
11868	
11869	      /* nothing to do if we aren't allowed to add more than one auxexpr per term */
11870	      if( conshdlrdata->bilinmaxnauxexprs <= 1 )
11871	         return SCIP_OKAY;
11872	
11873	      SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
11874	      auxvarexpr->cst = 0.0;
11875	      auxvarexpr->coefs[0] = 1.0;
11876	      auxvarexpr->coefs[1] = 0.0;
11877	      auxvarexpr->coefs[2] = 0.0;
11878	      auxvarexpr->auxvar = term->aux.var;
11879	      auxvarexpr->underestimate = term->nlocksneg > 0;
11880	      auxvarexpr->overestimate = term->nlockspos > 0;
11881	
11882	      /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
11883	      term->aux.exprs = NULL;
11884	
11885	      SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
11886	
11887	      /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
11888	      assert(added);
11889	   }
11890	
11891	   /* create and add auxexpr */
11892	   SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
11893	   auxexpr->underestimate = !overestimate;
11894	   auxexpr->overestimate = overestimate;
11895	   auxexpr->auxvar = auxvar;
11896	   auxexpr->coefs[0] = coefaux;
11897	   if( term->x == x )
11898	   {
11899	      assert(term->y == y);
11900	      auxexpr->coefs[1] = coefx;
11901	      auxexpr->coefs[2] = coefy;
11902	   }
11903	   else
11904	   {
11905	      assert(term->x == y);
11906	      assert(term->y == x);
11907	      auxexpr->coefs[1] = coefy;
11908	      auxexpr->coefs[2] = coefx;
11909	   }
11910	   auxexpr->cst = cst;
11911	   SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
11912	
11913	   if( !added )
11914	   {
11915	      SCIPfreeBlockMemory(scip, &auxexpr);
11916	   }
11917	   else if( auxvar != NULL )
11918	   { /* capture auxiliary variable */
11919	      SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
11920	   }
11921	
11922	   return SCIP_OKAY;
11923	}
11924	
11925	/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
11926	SCIP_RETCODE SCIPcomputeFacetVertexPolyhedralNonlinear(
11927	   SCIP*                 scip,               /**< SCIP data structure */
11928	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
11929	   SCIP_Bool             overestimate,       /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
11930	   SCIP_DECL_VERTEXPOLYFUN((*function)),     /**< pointer to vertex polyhedral function */
11931	   void*                 fundata,            /**< data for function evaluation (can be NULL) */
11932	   SCIP_Real*            xstar,              /**< point to be separated */
11933	   SCIP_Real*            box,                /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
11934	   int                   nallvars,           /**< half of the length of box */
11935	   SCIP_Real             targetvalue,        /**< target value: no need to compute facet if value in xstar would be worse than this value */
11936	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
11937	   SCIP_Real*            facetcoefs,         /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
11938	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
11939	   )
11940	{
11941	   SCIP_Real* corner;
11942	   SCIP_Real* funvals;
11943	   int* nonfixedpos;
11944	   SCIP_Real maxfaceterror;
11945	   int nvars; /* number of nonfixed variables */
11946	   unsigned int ncorners;
11947	   unsigned int i;
11948	   int j;
11949	
11950	   assert(scip != NULL);
11951	   assert(conshdlr != NULL);
11952	   assert(function != NULL);
11953	   assert(xstar != NULL);
11954	   assert(box != NULL);
11955	   assert(success != NULL);
11956	   assert(facetcoefs != NULL);
11957	   assert(facetconstant != NULL);
11958	
11959	   *success = FALSE;
11960	
11961	   /* identify fixed variables */
11962	   SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
11963	   nvars = 0;
11964	   for( j = 0; j < nallvars; ++j )
11965	   {
11966	      if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
11967	         continue;
11968	      nonfixedpos[nvars] = j;
11969	      nvars++;
11970	   }
11971	
11972	   /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
11973	    * if too many variables are not fixed, then we do nothing currently
11974	    */
11975	   if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
11976	   {
11977	      SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
11978	      SCIPfreeBufferArray(scip, &nonfixedpos);
11979	      return SCIP_OKAY;
11980	   }
11981	
11982	   /* compute f(v^i) for each corner v^i of [l,u] */
11983	   ncorners = POWEROFTWO(nvars);
11984	   SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
11985	   SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
11986	   for( j = 0; j < nallvars; ++j )
11987	   {
11988	      if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
11989	         corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
11990	   }
11991	   for( i = 0; i < ncorners; ++i )
11992	   {
11993	      SCIPdebugMsg(scip, "corner %u: ", i);
11994	      for( j = 0; j < nvars; ++j )
11995	      {
11996	         int varpos = nonfixedpos[j];
11997	         /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
11998	          * we check this by shifting i for j positions to the right and checking whether the last bit is set
11999	          */
12000	         if( (i >> j) & 0x1 )
12001	            corner[varpos] = box[2 * varpos + 1]; /* ub of var */
12002	         else
12003	            corner[varpos] = box[2 * varpos ]; /* lb of var */
12004	         SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
12005	         assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
12006	      }
12007	
12008	      funvals[i] = function(corner, nallvars, fundata);
12009	
12010	      SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
12011	
12012	      if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
12013	      {
12014	         SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
12015	         goto CLEANUP;
12016	      }
12017	   }
12018	
12019	   /* clear coefs array; below we only fill in coefs for nonfixed variables */
12020	   BMSclearMemoryArray(facetcoefs, nallvars);
12021	
12022	   if( nvars == 1 )
12023	   {
12024	      SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
12025	
12026	      /* check whether target has been missed */
12027	      if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
12028	      {
12029	         SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
12030	         *success = FALSE;
12031	      }
12032	   }
12033	   else if( nvars == 2 )
12034	   {
12035	      int idx1 = nonfixedpos[0];
12036	      int idx2 = nonfixedpos[1];
12037	      SCIP_Real p1[2] = { box[2*idx1],   box[2*idx2]   }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
12038	      SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2]   }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
12039	      SCIP_Real p3[2] = { box[2*idx1],   box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
12040	      SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
12041	      SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
12042	      SCIP_Real coefs[2] = { 0.0, 0.0 };
12043	
12044	      SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
12045	
12046	      facetcoefs[idx1] = coefs[0];
12047	      facetcoefs[idx2] = coefs[1];
12048	   }
12049	   else
12050	   {
12051	      SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
12052	   }
12053	   if( !*success )
12054	   {
12055	      SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
12056	      goto CLEANUP;
12057	   }
12058	
12059	   /*
12060	    *  check and adjust facet with the algorithm of Rikun et al.
12061	    */
12062	
12063	   maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
12064	
12065	   /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
12066	   if( maxfaceterror > 0.0 )
12067	   {
12068	      SCIP_CONSHDLRDATA* conshdlrdata;
12069	      SCIP_Real midval;
12070	      SCIP_Real feastol;
12071	
12072	      feastol = SCIPgetStage(scip) == SCIP_STAGE_SOLVING ? SCIPgetLPFeastol(scip) : SCIPfeastol(scip);
12073	
12074	      /* evaluate function in middle point to get some idea for a scaling */
12075	      for( j = 0; j < nvars; ++j )
12076	         corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
12077	      midval = function(corner, nallvars, fundata);
12078	      if( midval == SCIP_INVALID )
12079	         midval = 1.0;
12080	
12081	      conshdlrdata = SCIPconshdlrGetData(conshdlr);
12082	      assert(conshdlrdata != NULL);
12083	
12084	      /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
12085	      if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
12086	      {
12087	         SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
12088	         *success = FALSE;
12089	         goto CLEANUP;
12090	      }
12091	
12092	      SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
12093	
12094	      if( overestimate )
12095	         *facetconstant += maxfaceterror;
12096	      else
12097	         *facetconstant -= maxfaceterror;
12098	   }
12099	
12100	   /* if we made it until here, then we have a nice facet */
12101	   assert(*success);
12102	
12103	CLEANUP:
12104	   /* free allocated memory */
12105	   SCIPfreeBufferArray(scip, &corner);
12106	   SCIPfreeBufferArray(scip, &funvals);
12107	   SCIPfreeBufferArray(scip, &nonfixedpos);
12108	
12109	   return SCIP_OKAY;
12110	}
12111	
12112	/*
12113	 * constraint specific interface methods
12114	 */
12115	
12116	/** returns the expression of the given nonlinear constraint */
12117	SCIP_EXPR* SCIPgetExprNonlinear(
12118	   SCIP_CONS*            cons                /**< constraint data */
12119	   )
12120	{
12121	   SCIP_CONSDATA* consdata;
12122	
12123	   assert(cons != NULL);
12124	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12125	
12126	   consdata = SCIPconsGetData(cons);
12127	   assert(consdata != NULL);
12128	
12129	   return consdata->expr;
12130	}
12131	
12132	/** gets the left hand side of a nonlinear constraint */
12133	SCIP_Real SCIPgetLhsNonlinear(
12134	   SCIP_CONS*            cons                /**< constraint data */
12135	   )
12136	{
12137	   SCIP_CONSDATA* consdata;
12138	
12139	   assert(cons != NULL);
12140	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12141	
12142	   consdata = SCIPconsGetData(cons);
12143	   assert(consdata != NULL);
12144	
12145	   return consdata->lhs;
12146	}
12147	
12148	/** gets the right hand side of a nonlinear constraint */
12149	SCIP_Real SCIPgetRhsNonlinear(
12150	   SCIP_CONS*            cons                /**< constraint data */
12151	   )
12152	{
12153	   SCIP_CONSDATA* consdata;
12154	
12155	   assert(cons != NULL);
12156	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12157	
12158	   consdata = SCIPconsGetData(cons);
12159	   assert(consdata != NULL);
12160	
12161	   return consdata->rhs;
12162	}
12163	
12164	/** gets the nonlinear constraint as a nonlinear row representation. */
12165	SCIP_RETCODE SCIPgetNlRowNonlinear(
12166	   SCIP*                 scip,               /**< SCIP data structure */
12167	   SCIP_CONS*            cons,               /**< constraint */
12168	   SCIP_NLROW**          nlrow               /**< pointer to store nonlinear row */
12169	   )
12170	{
12171	   SCIP_CONSDATA* consdata;
12172	
12173	   assert(cons  != NULL);
12174	   assert(nlrow != NULL);
12175	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12176	
12177	   consdata = SCIPconsGetData(cons);
12178	   assert(consdata != NULL);
12179	
12180	   if( consdata->nlrow == NULL )
12181	   {
12182	      SCIP_CALL( createNlRow(scip, cons) );
12183	   }
12184	   assert(consdata->nlrow != NULL);
12185	   *nlrow = consdata->nlrow;
12186	
12187	   return SCIP_OKAY;
12188	}
12189	
12190	/** returns the curvature of the expression of a given nonlinear constraint
12191	 *
12192	 * @note The curvature information is computed during CONSINITSOL.
12193	 */
12194	SCIP_EXPRCURV SCIPgetCurvatureNonlinear(
12195	   SCIP_CONS*            cons                /**< constraint data */
12196	   )
12197	{
12198	   SCIP_CONSDATA* consdata;
12199	
12200	   assert(cons != NULL);
12201	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12202	
12203	   consdata = SCIPconsGetData(cons);
12204	   assert(consdata != NULL);
12205	
12206	   return consdata->curv;
12207	}
12208	
12209	/** checks whether expression of constraint can be represented as quadratic form
12210	 *
12211	 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
12212	 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
12213	 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
12214	 */
12215	SCIP_RETCODE SCIPcheckQuadraticNonlinear(
12216	   SCIP*                 scip,               /**< SCIP data structure */
12217	   SCIP_CONS*            cons,               /**< constraint data */
12218	   SCIP_Bool*            isquadratic         /**< buffer to store whether constraint is quadratic */
12219	   )
12220	{
12221	   SCIP_CONSDATA* consdata;
12222	
12223	   assert(scip != NULL);
12224	   assert(cons != NULL);
12225	   assert(isquadratic != NULL);
12226	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12227	
12228	   consdata = SCIPconsGetData(cons);
12229	   assert(consdata != NULL);
12230	   assert(consdata->expr != NULL);
12231	
12232	   /* check whether constraint expression is quadratic in extended formulation */
12233	   SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
12234	
12235	   /* if not quadratic in non-extended formulation, then do indicate quadratic */
12236	   if( *isquadratic )
12237	      *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
12238	
12239	   return SCIP_OKAY;
12240	}
12241	
12242	/** changes left-hand-side of a nonlinear constraint
12243	 *
12244	 * @attention This method can only be called in the problem stage.
12245	 */
12246	SCIP_RETCODE SCIPchgLhsNonlinear(
12247	   SCIP*                 scip,               /**< SCIP data structure */
12248	   SCIP_CONS*            cons,               /**< constraint data */
12249	   SCIP_Real             lhs                 /**< new left-hand-side */
12250	   )
12251	{
12252	   SCIP_CONSDATA* consdata;
12253	
12254	   assert(scip != NULL);
12255	   assert(cons != NULL);
12256	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12257	
12258	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12259	   {
12260	      SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12261	      return SCIP_INVALIDCALL;
12262	   }
12263	
12264	   /* we should have an original constraint */
12265	   assert(SCIPconsIsOriginal(cons));
12266	
12267	   consdata = SCIPconsGetData(cons);
12268	   assert(consdata != NULL);
12269	
12270	   if( consdata->lhs == lhs )
12271	      return SCIP_OKAY;
12272	
12273	   consdata->lhs = lhs;
12274	
12275	   /* not sure we care about any of these flags for original constraints */
12276	   consdata->ispropagated = FALSE;
12277	
12278	   return SCIP_OKAY;
12279	}
12280	
12281	/** changes right-hand-side of a nonlinear constraint
12282	 *
12283	 * @attention This method can only be called in the problem stage.
12284	 */
12285	SCIP_RETCODE SCIPchgRhsNonlinear(
12286	   SCIP*                 scip,               /**< SCIP data structure */
12287	   SCIP_CONS*            cons,               /**< constraint data */
12288	   SCIP_Real             rhs                 /**< new right-hand-side */
12289	   )
12290	{
12291	   SCIP_CONSDATA* consdata;
12292	
12293	   assert(scip != NULL);
12294	   assert(cons != NULL);
12295	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12296	
12297	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12298	   {
12299	      SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12300	      return SCIP_INVALIDCALL;
12301	   }
12302	
12303	   /* we should have an original constraint */
12304	   assert(SCIPconsIsOriginal(cons));
12305	
12306	   consdata = SCIPconsGetData(cons);
12307	   assert(consdata != NULL);
12308	
12309	   if( consdata->rhs == rhs )
12310	      return SCIP_OKAY;
12311	
12312	   consdata->rhs = rhs;
12313	
12314	   /* not sure we care about any of these flags for original constraints */
12315	   consdata->ispropagated = FALSE;
12316	
12317	   return SCIP_OKAY;
12318	}
12319	
12320	/** changes expression of a nonlinear constraint
12321	 *
12322	 * @attention This method can only be called in the problem stage.
12323	 */
12324	SCIP_RETCODE SCIPchgExprNonlinear(
12325	   SCIP*                 scip,               /**< SCIP data structure */
12326	   SCIP_CONS*            cons,               /**< constraint data */
12327	   SCIP_EXPR*            expr                /**< new expression */
12328	   )
12329	{
12330	   SCIP_CONSHDLR* conshdlr;
12331	   SCIP_CONSDATA* consdata;
12332	
12333	   assert(scip != NULL);
12334	   assert(cons != NULL);
12335	   assert(expr != NULL);
12336	
12337	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12338	   {
12339	      SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
12340	      return SCIP_INVALIDCALL;
12341	   }
12342	
12343	   /* we should have an original constraint */
12344	   assert(SCIPconsIsOriginal(cons));
12345	
12346	   conshdlr = SCIPconsGetHdlr(cons);
12347	   assert(conshdlr != NULL);
12348	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12349	
12350	   consdata = SCIPconsGetData(cons);
12351	   assert(consdata != NULL);
12352	   assert(consdata->expr != NULL);
12353	
12354	   /* we should not have collected additional data for the expr
12355	    * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12356	    */
12357	   assert(consdata->nvarexprs == 0);
12358	   assert(consdata->varexprs == NULL);
12359	   assert(!consdata->catchedevents);
12360	
12361	   SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
12362	
12363	   /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12364	   SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12365	
12366	   /* not sure we care about any of these flags for original constraints */
12367	   consdata->curv = SCIP_EXPRCURV_UNKNOWN;
12368	   consdata->issimplified = FALSE;
12369	   consdata->ispropagated = FALSE;
12370	
12371	   return SCIP_OKAY;
12372	}
12373	
12374	/** adds coef * var to nonlinear constraint
12375	 *
12376	 * @attention This method can only be called in the problem stage.
12377	 */
12378	SCIP_RETCODE SCIPaddLinearVarNonlinear(
12379	   SCIP*                 scip,               /**< SCIP data structure */
12380	   SCIP_CONS*            cons,               /**< constraint data */
12381	   SCIP_VAR*             var,                /**< variable */
12382	   SCIP_Real             coef                /**< coefficient */
12383	   )
12384	{
12385	   SCIP_CONSHDLR* conshdlr;
12386	   SCIP_CONSDATA* consdata;
12387	   SCIP_EXPR* varexpr;
12388	
12389	   assert(scip != NULL);
12390	   assert(cons != NULL);
12391	
12392	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12393	   {
12394	      SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12395	      return SCIP_INVALIDCALL;
12396	   }
12397	
12398	   /* we should have an original constraint */
12399	   assert(SCIPconsIsOriginal(cons));
12400	
12401	   if( coef == 0.0 )
12402	      return SCIP_OKAY;
12403	
12404	   conshdlr = SCIPconsGetHdlr(cons);
12405	   assert(conshdlr != NULL);
12406	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12407	
12408	   consdata = SCIPconsGetData(cons);
12409	   assert(consdata != NULL);
12410	   assert(consdata->expr != NULL);
12411	
12412	   /* we should not have collected additional data for it
12413	    * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12414	    */
12415	   assert(consdata->nvarexprs == 0);
12416	   assert(consdata->varexprs == NULL);
12417	   assert(!consdata->catchedevents);
12418	
12419	   SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
12420	
12421	   /* append to sum, if consdata->expr is sum and not used anywhere else */
12422	   if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12423	   {
12424	      SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
12425	   }
12426	   else
12427	   {
12428	      /* create new expression = 1 * consdata->expr + coef * var */
12429	      SCIP_EXPR* children[2] = { consdata->expr, varexpr };
12430	      SCIP_Real coefs[2] = { 1.0, coef };
12431	
12432	      SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12433	
12434	      /* release old root expr */
12435	      SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12436	   }
12437	
12438	   SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12439	
12440	   /* not sure we care about any of these flags for original constraints */
12441	   consdata->issimplified = FALSE;
12442	   consdata->ispropagated = FALSE;
12443	
12444	   return SCIP_OKAY;
12445	}
12446	
12447	/** adds coef * expr to nonlinear constraint
12448	 *
12449	 * @attention This method can only be called in the problem stage.
12450	 */
12451	SCIP_RETCODE SCIPaddExprNonlinear(
12452	   SCIP*                 scip,               /**< SCIP data structure */
12453	   SCIP_CONS*            cons,               /**< nonlinear constraint */
12454	   SCIP_EXPR*            expr,               /**< expression */
12455	   SCIP_Real             coef                /**< coefficient */
12456	   )
12457	{
12458	   SCIP_CONSHDLR* conshdlr;
12459	   SCIP_CONSDATA* consdata;
12460	   SCIP_EXPR* exprowned;
12461	
12462	   assert(scip != NULL);
12463	   assert(cons != NULL);
12464	
12465	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12466	   {
12467	      SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12468	      return SCIP_INVALIDCALL;
12469	   }
12470	
12471	   /* we should have an original constraint */
12472	   assert(SCIPconsIsOriginal(cons));
12473	
12474	   if( coef == 0.0 )
12475	      return SCIP_OKAY;
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 it
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	   /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12493	   SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12494	
12495	   /* append to sum, if consdata->expr is sum and not used anywhere else */
12496	   if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12497	   {
12498	      SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
12499	   }
12500	   else
12501	   {
12502	      /* create new expression = 1 * consdata->expr + coef * var */
12503	      SCIP_EXPR* children[2] = { consdata->expr, exprowned };
12504	      SCIP_Real coefs[2] = { 1.0, coef };
12505	
12506	      SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12507	
12508	      /* release old root expr */
12509	      SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12510	   }
12511	
12512	   SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
12513	
12514	   /* not sure we care about any of these flags for original constraints */
12515	   consdata->issimplified = FALSE;
12516	   consdata->ispropagated = FALSE;
12517	
12518	   return SCIP_OKAY;
12519	}
12520	
12521	/** gets absolute violation of nonlinear constraint
12522	 *
12523	 * This function evaluates the constraints in the given solution.
12524	 *
12525	 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
12526	 */
12527	SCIP_RETCODE SCIPgetAbsViolationNonlinear(
12528	   SCIP*                 scip,               /**< SCIP data structure */
12529	   SCIP_CONS*            cons,               /**< constraint */
12530	   SCIP_SOL*             sol,                /**< solution to check */
12531	   SCIP_Real*            viol                /**< buffer to store computed violation */
12532	   )
12533	{
12534	   assert(cons != NULL);
12535	   assert(viol != NULL);
12536	
12537	   SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12538	   *viol = getConsAbsViolation(cons);
12539	
12540	   return SCIP_OKAY;
12541	}
12542	
12543	/** gets scaled violation of nonlinear constraint
12544	 *
12545	 * This function evaluates the constraints in the given solution.
12546	 *
12547	 * The scaling that is applied to the absolute violation of the constraint
12548	 * depends on the setting of parameter constraints/nonlinear/violscale.
12549	 */
12550	SCIP_RETCODE SCIPgetRelViolationNonlinear(
12551	   SCIP*                 scip,               /**< SCIP data structure */
12552	   SCIP_CONS*            cons,               /**< constraint */
12553	   SCIP_SOL*             sol,                /**< solution to check */
12554	   SCIP_Real*            viol                /**< buffer to store computed violation */
12555	   )
12556	{
12557	   assert(cons != NULL);
12558	   assert(viol != NULL);
12559	
12560	   SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12561	   SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
12562	
12563	   return SCIP_OKAY;
12564	}
12565	
12566	/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
12567	void SCIPgetLinvarMayDecreaseNonlinear(
12568	   SCIP*                 scip,               /**< SCIP data structure */
12569	   SCIP_CONS*            cons,               /**< nonlinear constraint */
12570	   SCIP_VAR**            var,                /**< pointer to store the variable */
12571	   SCIP_Real*            coef                /**< pointer to store the coefficient */
12572	   )
12573	{
12574	   SCIP_CONSDATA* consdata;
12575	
12576	   assert(cons != NULL);
12577	   assert(var != NULL);
12578	   assert(coef != NULL);
12579	
12580	   /* check for a linear variable that can be increased or decreased without harming feasibility */
12581	   findUnlockedLinearVar(scip, cons);
12582	
12583	   consdata = SCIPconsGetData(cons);
12584	   assert(consdata != NULL);
12585	
12586	   *var = consdata->linvardecr;
12587	   *coef = consdata->linvardecrcoef;
12588	}
12589	
12590	/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
12591	void SCIPgetLinvarMayIncreaseNonlinear(
12592	   SCIP*                 scip,               /**< SCIP data structure */
12593	   SCIP_CONS*            cons,               /**< nonlinear constraint */
12594	   SCIP_VAR**            var,                /**< pointer to store the variable */
12595	   SCIP_Real*            coef                /**< pointer to store the coefficient */
12596	   )
12597	{
12598	   SCIP_CONSDATA* consdata;
12599	
12600	   assert(cons != NULL);
12601	   assert(var != NULL);
12602	   assert(coef != NULL);
12603	
12604	   /* check for a linear variable that can be increased or decreased without harming feasibility */
12605	   findUnlockedLinearVar(scip, cons);
12606	
12607	   consdata = SCIPconsGetData(cons);
12608	   assert(consdata != NULL);
12609	
12610	   *var = consdata->linvarincr;
12611	   *coef = consdata->linvarincrcoef;
12612	}
12613	
12614	
12615	/*
12616	 * Methods for Expressions in Nonlinear Constraints
12617	 */
12618	
12619	/** returns the number of positive rounding locks of an expression */
12620	int SCIPgetExprNLocksPosNonlinear(
12621	   SCIP_EXPR*            expr                /**< expression */
12622	   )
12623	{
12624	   assert(expr != NULL);
12625	   assert(SCIPexprGetOwnerData(expr) != NULL);
12626	
12627	   return SCIPexprGetOwnerData(expr)->nlockspos;
12628	}
12629	
12630	/** returns the number of negative rounding locks of an expression */
12631	int SCIPgetExprNLocksNegNonlinear(
12632	   SCIP_EXPR*            expr                /**< expression */
12633	   )
12634	{
12635	   assert(expr != NULL);
12636	   assert(SCIPexprGetOwnerData(expr) != NULL);
12637	
12638	   return SCIPexprGetOwnerData(expr)->nlocksneg;
12639	}
12640	
12641	/** returns the variable used for linearizing a given expression (return value might be NULL)
12642	 *
12643	 * @note for variable expression it returns the corresponding variable
12644	 */
12645	SCIP_VAR* SCIPgetExprAuxVarNonlinear(
12646	   SCIP_EXPR*            expr                /**< expression */
12647	   )
12648	{
12649	   SCIP_EXPR_OWNERDATA* ownerdata;
12650	
12651	   assert(expr != NULL);
12652	
12653	   ownerdata = SCIPexprGetOwnerData(expr);
12654	   assert(ownerdata != NULL);
12655	
12656	   return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
12657	}
12658	
12659	/** returns the number of enforcements for an expression */
12660	int SCIPgetExprNEnfosNonlinear(
12661	   SCIP_EXPR*            expr                /**< expression */
12662	   )
12663	{
12664	   assert(expr != NULL);
12665	   assert(SCIPexprGetOwnerData(expr) != NULL);
12666	
12667	   return SCIPexprGetOwnerData(expr)->nenfos;
12668	}
12669	
12670	/** returns the data for one of the enforcements of an expression */
12671	void SCIPgetExprEnfoDataNonlinear(
12672	   SCIP_EXPR*            expr,               /**< expression */
12673	   int                   idx,                /**< position of enforcement in enfos array */
12674	   SCIP_NLHDLR**         nlhdlr,             /**< buffer to store nlhldr */
12675	   SCIP_NLHDLREXPRDATA** nlhdlrexprdata,     /**< buffer to store nlhdlr data for expression, or NULL */
12676	   SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
12677	   SCIP_Bool*            sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
12678	   SCIP_Bool*            sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
12679	   SCIP_Real*            auxvalue            /**< buffer to store current auxvalue, or NULL */
12680	   )
12681	{
12682	   SCIP_EXPR_OWNERDATA* ownerdata;
12683	
12684	   assert(expr != NULL);
12685	
12686	   ownerdata = SCIPexprGetOwnerData(expr);
12687	   assert(ownerdata != NULL);
12688	   assert(idx >= 0);
12689	   assert(idx < ownerdata->nenfos);
12690	   assert(ownerdata->enfos[idx] != NULL);
12691	   assert(nlhdlr != NULL);
12692	
12693	   *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
12694	
12695	   if( nlhdlrexprdata != NULL )
12696	      *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
12697	
12698	   if( nlhdlrparticipation != NULL )
12699	      *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
12700	
12701	   if( sepabelowusesactivity != NULL )
12702	      *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
12703	
12704	   if( sepaaboveusesactivity != NULL )
12705	      *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
12706	
12707	   if( auxvalue != NULL )
12708	      *auxvalue = ownerdata->enfos[idx]->auxvalue;
12709	}
12710	
12711	/** sets the auxiliary value of expression for one of the enforcements of an expression */
12712	void SCIPsetExprEnfoAuxValueNonlinear(
12713	   SCIP_EXPR*            expr,               /**< expression */
12714	   int                   idx,                /**< position of enforcement in enfos array */
12715	   SCIP_Real             auxvalue            /**< the new value of auxval */
12716	   )
12717	{
12718	   SCIP_EXPR_OWNERDATA* ownerdata;
12719	
12720	   assert(expr != NULL);
12721	
12722	   ownerdata = SCIPexprGetOwnerData(expr);
12723	   assert(ownerdata != NULL);
12724	
12725	   assert(idx >= 0);
12726	   assert(idx < ownerdata->nenfos);
12727	   assert(ownerdata->enfos[idx] != NULL);
12728	
12729	   ownerdata->enfos[idx]->auxvalue = auxvalue;
12730	}
12731	
12732	/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
12733	 *
12734	 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12735	 */
12736	unsigned int SCIPgetExprNPropUsesActivityNonlinear(
12737	   SCIP_EXPR*            expr                /**< expression */
12738	   )
12739	{
12740	   assert(expr != NULL);
12741	   assert(SCIPexprGetOwnerData(expr) != NULL);
12742	
12743	   return SCIPexprGetOwnerData(expr)->nactivityusesprop;
12744	}
12745	
12746	/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
12747	 *
12748	 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12749	 */
12750	unsigned int SCIPgetExprNSepaUsesActivityNonlinear(
12751	   SCIP_EXPR*            expr                /**< expression */
12752	   )
12753	{
12754	   assert(expr != NULL);
12755	   assert(SCIPexprGetOwnerData(expr) != NULL);
12756	
12757	   return SCIPexprGetOwnerData(expr)->nactivityusessepa;
12758	}
12759	
12760	/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
12761	 *
12762	 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12763	 */
12764	unsigned int SCIPgetExprNAuxvarUsesNonlinear(
12765	   SCIP_EXPR*            expr                /**< expression */
12766	   )
12767	{
12768	   assert(expr != NULL);
12769	   assert(SCIPexprGetOwnerData(expr) != NULL);
12770	
12771	   return SCIPexprGetOwnerData(expr)->nauxvaruses;
12772	}
12773	
12774	/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
12775	 *
12776	 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
12777	 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
12778	 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
12779	 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
12780	 *   and also increments this count for all variables in the expression.
12781	 *
12782	 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
12783	 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
12784	 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
12785	 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
12786	 */
12787	SCIP_RETCODE SCIPregisterExprUsageNonlinear(
12788	   SCIP*                 scip,               /**< SCIP data structure */
12789	   SCIP_EXPR*            expr,               /**< expression */
12790	   SCIP_Bool             useauxvar,          /**< whether an auxiliary variable will be used for estimate or cut generation */
12791	   SCIP_Bool             useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
12792	   SCIP_Bool             useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
12793	   SCIP_Bool             useactivityforsepaabove  /**< whether activity of expr will be used by overestimation */
12794	   )
12795	{
12796	   SCIP_EXPR_OWNERDATA* ownerdata;
12797	
12798	   assert(expr != NULL);
12799	
12800	   ownerdata = SCIPexprGetOwnerData(expr);
12801	   assert(ownerdata != NULL);
12802	
12803	   /* do not store auxvar request for variable expressions */
12804	   if( useauxvar && SCIPisExprVar(scip, expr) )
12805	      useauxvar = FALSE;
12806	
12807	   if( ownerdata->nenfos >= 0 &&
12808	      ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
12809	        (ownerdata->nauxvaruses == 0 && useauxvar)
12810	      ) )
12811	   {
12812	      /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
12813	       * we require additional enforcement methods, that is,
12814	       * - activity of expr was not used before but will be used now, or
12815	       * - auxiliary variable of expr was not required before but will be used now
12816	       */
12817	      SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
12818	   }
12819	
12820	   if( useauxvar )
12821	      ++ownerdata->nauxvaruses;
12822	
12823	   if( useactivityforprop )
12824	      ++ownerdata->nactivityusesprop;
12825	
12826	   if( useactivityforsepabelow || useactivityforsepaabove )
12827	      ++ownerdata->nactivityusessepa;
12828	
12829	   /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
12830	    * information is used in detectNlhdlr()
12831	    */
12832	   if( useactivityforsepabelow )
12833	      SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
12834	   if( useactivityforsepaabove )
12835	      SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
12836	
12837	   if( useactivityforprop )
12838	   {
12839	      /* if activity will be used for propagation, then make sure there is a valid activity
12840	       * this way, we can do a reversepropcall after detectNlhdlr
12841	       */
12842	      SCIP_CALL( SCIPevalExprActivity(scip, expr) );
12843	   }
12844	
12845	   /* increase the nactivityusedsepa counter for all variables used in the given expression */
12846	   if(( useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
12847	   {
12848	      SCIP_EXPRITER* it;
12849	
12850	      /* create and initialize iterator */
12851	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
12852	      SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, FALSE) );
12853	
12854	      for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
12855	         if( SCIPisExprVar(scip, expr) )
12856	            ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
12857	
12858	      /* free iterator */
12859	      SCIPfreeExpriter(&it);
12860	   }
12861	
12862	   return SCIP_OKAY;
12863	}
12864	
12865	/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
12866	 *
12867	 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
12868	 * Assume that f(x) is associated with auxiliary variable z.
12869	 *
12870	 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
12871	 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
12872	 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
12873	 *
12874	 * If necessary, f is evaluated in the given solution. If that fails (domain error),
12875	 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
12876	 */
12877	SCIP_RETCODE SCIPgetExprAbsOrigViolationNonlinear(
12878	   SCIP*                 scip,               /**< SCIP data structure */
12879	   SCIP_EXPR*            expr,               /**< expression */
12880	   SCIP_SOL*             sol,                /**< solution */
12881	   SCIP_Longint          soltag,             /**< tag of solution */
12882	   SCIP_Real*            viol,               /**< buffer to store computed violation */
12883	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(x) is violated, or NULL */
12884	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(x) is violated, or NULL */
12885	   )
12886	{
12887	   assert(scip != NULL);
12888	   assert(expr != NULL);
12889	   assert(viol != NULL);
12890	
12891	   /* make sure expression has been evaluated */
12892	   SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
12893	
12894	   /* get violation from internal method */
12895	   *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
12896	
12897	   return SCIP_OKAY;
12898	}
12899	
12900	/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
12901	 *
12902	 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
12903	 * Assume that f(w) is associated with auxiliary variable z.
12904	 *
12905	 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
12906	 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
12907	 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
12908	 *
12909	 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
12910	 * both `violover` and `violunder` are set to TRUE.
12911	 */
12912	SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(
12913	   SCIP*                 scip,               /**< SCIP data structure */
12914	   SCIP_EXPR*            expr,               /**< expression */
12915	   SCIP_Real             auxvalue,           /**< the value of f(w) */
12916	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
12917	   SCIP_Real*            viol,               /**< buffer to store computed violation */
12918	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(w) is violated, or NULL */
12919	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(w) is violated, or NULL */
12920	   )
12921	{
12922	   assert(scip != NULL);
12923	   assert(expr != NULL);
12924	   assert(viol != NULL);
12925	
12926	   /* get violation from internal method */
12927	   *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
12928	
12929	   return SCIP_OKAY;
12930	}
12931	
12932	
12933	/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
12934	 *
12935	 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
12936	 * Assume that f(w) is associated with auxiliary variable z.
12937	 *
12938	 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
12939	 * the absolute violation divided by max(1,|f(w)|).
12940	 *
12941	 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
12942	 * both `violover` and `violunder` are set to TRUE.
12943	 */
12944	SCIP_RETCODE SCIPgetExprRelAuxViolationNonlinear(
12945	   SCIP*                 scip,               /**< SCIP data structure */
12946	   SCIP_EXPR*            expr,               /**< expression */
12947	   SCIP_Real             auxvalue,           /**< the value of f(w) */
12948	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
12949	   SCIP_Real*            viol,               /**< buffer to store computed violation */
12950	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(w) is violated, or NULL */
12951	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(w) is violated, or NULL */
12952	   )
12953	{
12954	   assert(scip != NULL);
12955	   assert(expr != NULL);
12956	   assert(viol != NULL);
12957	
12958	   /* get violation from internal method */
12959	   *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
12960	
12961	   if( !SCIPisInfinity(scip, *viol) )
12962	   {
12963	      assert(auxvalue != SCIP_INVALID);
12964	      /* TODO maybe we should rather use max(eps,|auxvalue|)? */
12965	      *viol /= MAX(1.0, REALABS(auxvalue));
12966	   }
12967	
12968	   return SCIP_OKAY;
12969	}
12970	
12971	/** returns bounds on the expression
12972	 *
12973	 * This gives an intersection of bounds from
12974	 * - activity calculation (SCIPexprGetActivity()), if valid,
12975	 * - auxiliary variable, if present,
12976	 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
12977	 *
12978	 * @note The returned interval can be empty!
12979	 */
12980	SCIP_INTERVAL SCIPgetExprBoundsNonlinear(
12981	   SCIP*                 scip,               /**< SCIP data structure */
12982	   SCIP_EXPR*            expr                /**< expression */
12983	   )
12984	{
12985	   SCIP_EXPR_OWNERDATA* ownerdata;
12986	   SCIP_CONSHDLRDATA* conshdlrdata;
12987	   SCIP_INTERVAL bounds;
12988	
12989	   assert(scip != NULL);
12990	   assert(expr != NULL);
12991	
12992	   ownerdata = SCIPexprGetOwnerData(expr);
12993	   assert(ownerdata != NULL);
12994	
12995	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
12996	   assert(conshdlrdata != NULL);
12997	
12998	   /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
12999	
13000	   /* start with propbounds if they belong to current propagation */
13001	   if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13002	   {
13003	      bounds = ownerdata->propbounds;
13004	      /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
13005	   }
13006	   else
13007	      SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &bounds);
13008	
13009	   if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
13010	   {
13011	      /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
13012	      /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
13013	      SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), bounds);
13014	   }
13015	
13016	   if( ownerdata->auxvar != NULL )
13017	   {
13018	      /* apply auxiliary variable bounds to bounds */
13019	      SCIP_INTERVAL auxvarbounds;
13020	
13021	      auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
13022	      /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
13023	      SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
13024	   }
13025	
13026	   /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
13027	
13028	   return bounds;
13029	}
13030	
13031	/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
13032	 * corresponding (auxiliary) variable (if any)
13033	 *
13034	 * @attention this function should only be called during domain propagation in cons_nonlinear
13035	 */
13036	SCIP_RETCODE SCIPtightenExprIntervalNonlinear(
13037	   SCIP*                 scip,               /**< SCIP data structure */
13038	   SCIP_EXPR*            expr,               /**< expression to be tightened */
13039	   SCIP_INTERVAL         newbounds,          /**< new bounds for the expression */
13040	   SCIP_Bool*            cutoff,             /**< buffer to store whether a cutoff was detected */
13041	   int*                  ntightenings        /**< buffer to add the total number of tightenings, or NULL */
13042	   )
13043	{
13044	   SCIP_EXPR_OWNERDATA* ownerdata;
13045	   SCIP_CONSHDLRDATA* conshdlrdata;
13046	
13047	   assert(scip != NULL);
13048	   assert(expr != NULL);
13049	   assert(cutoff != NULL);
13050	
13051	   ownerdata = SCIPexprGetOwnerData(expr);
13052	   assert(ownerdata != NULL);
13053	   assert(ownerdata->conshdlr != NULL);
13054	
13055	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13056	   assert(conshdlrdata != NULL);
13057	
13058	   /* the code below assumes that current activity is valid
13059	    * if it turns out that we cannot ensure that, then we should change code
13060	    */
13061	   assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13062	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13063	
13064	   *cutoff = FALSE;
13065	
13066	#ifdef DEBUG_PROP
13067	   SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
13068	   SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
13069	   SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
13070	#endif
13071	
13072	   if( SCIPexprIsIntegral(expr) )
13073	   {
13074	      /* apply integrality to new bounds
13075	       * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
13076	       */
13077	      if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
13078	         newbounds.inf = SCIPceil(scip, newbounds.inf);
13079	      if( newbounds.sup <  SCIP_INTERVAL_INFINITY )
13080	         newbounds.sup = SCIPfloor(scip, newbounds.sup);
13081	#ifdef DEBUG_PROP
13082	      SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
13083	#endif
13084	   }
13085	
13086	   if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newbounds) )
13087	   {
13088	      SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
13089	
13090	      *cutoff = TRUE;
13091	      return SCIP_OKAY;
13092	   }
13093	
13094	   /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
13095	   if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
13096	   {
13097	      SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
13098	
13099	      *cutoff = TRUE;
13100	      return SCIP_OKAY;
13101	   }
13102	
13103	   /* tighten newbounds w.r.t. existing expr->propbounds or activity */
13104	   if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13105	   {
13106	      /* if already having propbounds in expr, then tighten newbounds by propbounds */
13107	      SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
13108	   }
13109	   else
13110	   {
13111	      /* first time we have propbounds for expr in this propagation rounds:
13112	       * intersect with activity (though don't let it become empty if very close intervals)
13113	       */
13114	      SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
13115	   }
13116	#ifdef DEBUG_PROP
13117	   SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
13118	#endif
13119	
13120	   /* check if the new bounds lead to an empty interval */
13121	   if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newbounds) )
13122	   {
13123	      SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
13124	
13125	      *cutoff = TRUE;
13126	      return SCIP_OKAY;
13127	   }
13128	
13129	   /* if expr is not constant or variable, then store newbounds in expr->propbounds
13130	    * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
13131	    * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
13132	    */
13133	   if( SCIPexprGetNChildren(expr) > 0 )
13134	   {
13135	      ownerdata->propbounds = newbounds;
13136	      ownerdata->propboundstag = conshdlrdata->curpropboundstag;
13137	   }
13138	
13139	   /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
13140	    * propagation or update of auxvar bounds
13141	    * TODO? if we first had a considerable tightening and then only get small tightenings under the same
13142	    *   curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
13143	    *   not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
13144	    *   propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
13145	    *   one or should we not even update propbounds to newbounds if the update is small?
13146	    */
13147	   if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
13148	   {
13149	#ifdef DEBUG_PROP
13150	      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);
13151	#endif
13152	      return SCIP_OKAY;
13153	   }
13154	
13155	   if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
13156	   {
13157	      /* add expression to propagation queue if not there yet and not var or constant and
13158	       * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
13159	       */
13160	#ifdef DEBUG_PROP
13161	         SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
13162	#endif
13163	         SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
13164	         ownerdata->inpropqueue = TRUE;
13165	   }
13166	
13167	   /* update bounds on variable or auxiliary variable */
13168	   SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
13169	
13170	   return SCIP_OKAY;
13171	}
13172	
13173	/** mark constraints that include this expression to be propagated again
13174	 *
13175	 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
13176	 * a change of variable bounds, e.g., because new information on the expression is available
13177	 * that could potentially lead to tighter expression activity values.
13178	 *
13179	 * Note, that this call marks also constraints for propagation which only share some variable
13180	 * with this expression.
13181	 */
13182	SCIP_RETCODE SCIPmarkExprPropagateNonlinear(
13183	   SCIP*                 scip,               /**< SCIP data structure */
13184	   SCIP_EXPR*            expr                /**< expression to propagate again */
13185	   )
13186	{
13187	   SCIP_EXPRITER* it;
13188	   SCIP_CONSDATA* consdata;
13189	   SCIP_EXPR_OWNERDATA* ownerdata;
13190	   int c;
13191	
13192	   assert(scip != NULL);
13193	   assert(expr != NULL);
13194	
13195	   ownerdata = SCIPexprGetOwnerData(expr);
13196	   assert(ownerdata != NULL);
13197	
13198	   SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
13199	
13200	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13201	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, FALSE) );
13202	
13203	   for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13204	   {
13205	      if( !SCIPisExprVar(scip, expr) )
13206	         continue;
13207	
13208	      ownerdata = SCIPexprGetOwnerData(expr);
13209	      assert(ownerdata != NULL);
13210	
13211	      for( c = 0; c < ownerdata->nconss; ++c )
13212	      {
13213	         consdata = SCIPconsGetData(ownerdata->conss[c]);
13214	         assert(consdata != NULL);
13215	         consdata->ispropagated = FALSE;
13216	      }
13217	   }
13218	
13219	   SCIPfreeExpriter(&it);
13220	
13221	   return SCIP_OKAY;
13222	}
13223	
13224	/** adds violation-branching score to an expression
13225	 *
13226	 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
13227	 * The expression must either be a variable expression or have an aux-variable.
13228	 * In the latter case, branching on auxiliary variables must have been enabled.
13229	 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
13230	 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
13231	 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
13232	 *
13233	 * @see SCIPaddExprsViolScoreNonlinear()
13234	 */
13235	void SCIPaddExprViolScoreNonlinear(
13236	   SCIP*                 scip,               /**< SCIP data structure */
13237	   SCIP_EXPR*            expr,               /**< expression where to add branching score */
13238	   SCIP_Real             violscore           /**< violation score to add to expression */
13239	   )
13240	{
13241	   SCIP_EXPR_OWNERDATA* ownerdata;
13242	   SCIP_CONSHDLRDATA* conshdlrdata;
13243	
13244	   assert(scip != NULL);
13245	   assert(expr != NULL);
13246	   assert(violscore >= 0.0);
13247	
13248	   ownerdata = SCIPexprGetOwnerData(expr);
13249	   assert(ownerdata != NULL);
13250	
13251	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13252	   assert(conshdlrdata != NULL);
13253	
13254	   /* if not allowing to branch on auxvars, then expr must be a var-expr */
13255	   assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
13256	   /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
13257	   assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
13258	
13259	   /* reset branching score if we are in a different enfo round */
13260	   if( ownerdata->violscoretag != conshdlrdata->enforound )
13261	   {
13262	      ownerdata->violscoresum = violscore;
13263	      ownerdata->violscoremax = violscore;
13264	      ownerdata->nviolscores = 1;
13265	      ownerdata->violscoretag = conshdlrdata->enforound;
13266	      return;
13267	   }
13268	
13269	   ownerdata->violscoresum += violscore;
13270	   if( violscore > ownerdata->violscoremax )
13271	      ownerdata->violscoremax = violscore;
13272	   ++ownerdata->nviolscores;
13273	}
13274	
13275	/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
13276	 *
13277	 * Each expression must either be a variable expression or have an aux-variable.
13278	 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
13279	 * variables present in `exprs`.
13280	 */
13281	SCIP_RETCODE SCIPaddExprsViolScoreNonlinear(
13282	   SCIP*                 scip,               /**< SCIP data structure */
13283	   SCIP_EXPR**           exprs,              /**< expressions where to add branching score */
13284	   int                   nexprs,             /**< number of expressions */
13285	   SCIP_Real             violscore,          /**< violation score to add to expression */
13286	   SCIP_SOL*             sol,                /**< current solution */
13287	   SCIP_Bool*            success             /**< buffer to store whether at least one violscore was added */
13288	   )
13289	{
13290	   SCIP_EXPRITER* it;
13291	   SCIP_EXPR** varexprs;
13292	   SCIP_EXPR* e;
13293	   int nvars;
13294	   int varssize;
13295	   int i;
13296	
13297	   assert(exprs != NULL || nexprs == 0);
13298	   assert(success != NULL);
13299	
13300	   if( nexprs == 0 )
13301	   {
13302	      *success = FALSE;
13303	      return SCIP_OKAY;
13304	   }
13305	
13306	   /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
13307	   if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
13308	   {
13309	      addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
13310	      return SCIP_OKAY;
13311	   }
13312	
13313	   /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
13314	   nvars = 0;
13315	   varssize = 5;
13316	   SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
13317	
13318	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13319	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
13320	
13321	   for( i = 0; i < nexprs; ++i )
13322	   {
13323	      for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
13324	      {
13325	         assert(e != NULL);
13326	
13327	         if( SCIPisExprVar(scip, e) )
13328	         {
13329	            /* add variable expression to vars array */
13330	            if( varssize == nvars )
13331	            {
13332	               varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
13333	               SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
13334	            }
13335	            assert(varssize > nvars);
13336	
13337	            varexprs[nvars++] = e;
13338	         }
13339	      }
13340	   }
13341	
13342	   SCIPfreeExpriter(&it);
13343	
13344	   addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
13345	
13346	   SCIPfreeBufferArray(scip, &varexprs);
13347	
13348	   return SCIP_OKAY;
13349	}
13350	
13351	/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
13352	SCIP_Real SCIPgetExprViolScoreNonlinear(
13353	   SCIP_EXPR*            expr                /**< expression */
13354	   )
13355	{
13356	   SCIP_EXPR_OWNERDATA* ownerdata;
13357	   SCIP_CONSHDLRDATA* conshdlrdata;
13358	
13359	   assert(expr != NULL);
13360	
13361	   ownerdata = SCIPexprGetOwnerData(expr);
13362	   assert(ownerdata != NULL);
13363	
13364	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13365	   assert(conshdlrdata != NULL);
13366	
13367	   if( conshdlrdata->enforound != ownerdata->violscoretag )
13368	      return 0.0;
13369	
13370	   if( ownerdata->nviolscores == 0 )
13371	      return 0.0;
13372	
13373	   switch( conshdlrdata->branchscoreagg )
13374	   {
13375	      case 'a' :
13376	         /* average */
13377	         return ownerdata->violscoresum / ownerdata->nviolscores;
13378	
13379	      case 'm' :
13380	         /* maximum */
13381	         return ownerdata->violscoremax;
13382	
13383	      case 's' :
13384	         /* sum */
13385	         return ownerdata->violscoresum;
13386	
13387	      default:
13388	         SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
13389	         SCIPABORT();
13390	         return SCIP_INVALID;
13391	   }
13392	}
13393	
13394	/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13395	 *
13396	 * @see SCIPexprGetDerivative()
13397	 */
13398	SCIP_Real SCIPgetExprPartialDiffNonlinear(
13399	   SCIP*                 scip,               /**< SCIP data structure */
13400	   SCIP_EXPR*            expr,               /**< root expression of constraint used in the last SCIPevalExprGradient() call */
13401	   SCIP_VAR*             var                 /**< variable (needs to be in the expression) */
13402	   )
13403	{
13404	   SCIP_EXPR_OWNERDATA* ownerdata;
13405	   SCIP_CONSHDLRDATA* conshdlrdata;
13406	   SCIP_EXPR* varexpr;
13407	
13408	   assert(scip != NULL);
13409	   assert(expr != NULL);
13410	   assert(var != NULL);
13411	
13412	   /* return 0.0 for value expression */
13413	   if( SCIPisExprValue(scip, expr) )
13414	   {
13415	      assert(SCIPexprGetDerivative(expr) == 0.0);
13416	      return 0.0;
13417	   }
13418	
13419	   /* check if an error occurred during the last SCIPevalExprGradient() call */
13420	   if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
13421	      return SCIP_INVALID;
13422	
13423	   ownerdata = SCIPexprGetOwnerData(expr);
13424	   assert(ownerdata != NULL);
13425	
13426	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13427	   assert(conshdlrdata != NULL);
13428	
13429	   /* use variable to expressions mapping which is stored in the constraint handler data */
13430	   assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13431	
13432	   varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13433	   assert(varexpr != NULL);
13434	   assert(SCIPisExprVar(scip, varexpr));
13435	
13436	   /* use difftag to decide whether the variable belongs to the expression */
13437	   return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
13438	}
13439	
13440	/** 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)
13441	 *
13442	 * @see SCIPexprGetBardot()
13443	 */
13444	SCIP_Real SCIPgetExprPartialDiffGradientDirNonlinear(
13445	   SCIP*                 scip,               /**< SCIP data structure */
13446	   SCIP_EXPR*            expr,               /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
13447	   SCIP_VAR*             var                 /**< variable (needs to be in the expression) */
13448	   )
13449	{
13450	   SCIP_EXPR_OWNERDATA* ownerdata;
13451	   SCIP_CONSHDLRDATA* conshdlrdata;
13452	   SCIP_EXPR* varexpr;
13453	
13454	   assert(scip != NULL);
13455	   assert(expr != NULL);
13456	   assert(var != NULL);
13457	
13458	   /* return 0.0 for value expression */
13459	   if( SCIPisExprValue(scip, expr) )
13460	      return 0.0;
13461	
13462	   /* check if an error occurred during the last SCIPevalExprHessianDir() call */
13463	   if( SCIPexprGetBardot(expr) == SCIP_INVALID )
13464	      return SCIP_INVALID;
13465	
13466	   ownerdata = SCIPexprGetOwnerData(expr);
13467	   assert(ownerdata != NULL);
13468	
13469	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13470	   assert(conshdlrdata != NULL);
13471	
13472	   /* use variable to expressions mapping which is stored in the constraint handler data;
13473	    * if this fails it means that we are asking for the var's component of H*u for a var
13474	    * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
13475	    */
13476	   assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13477	
13478	   varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13479	   assert(varexpr != NULL);
13480	   assert(SCIPisExprVar(scip, varexpr));
13481	
13482	   /* use difftag to decide whether the variable belongs to the expression */
13483	   return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
13484	}
13485	
13486	/** evaluates quadratic term in a solution w.r.t. auxiliary variables
13487	 *
13488	 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
13489	 */
13490	SCIP_Real SCIPevalExprQuadraticAuxNonlinear(
13491	   SCIP*                 scip,               /**< SCIP data structure */
13492	   SCIP_EXPR*            expr,               /**< quadratic expression */
13493	   SCIP_SOL*             sol                 /**< solution to evaluate, or NULL for LP solution */
13494	   )
13495	{
13496	   SCIP_Real auxvalue;
13497	   int nlinexprs;
13498	   SCIP_Real* lincoefs;
13499	   SCIP_EXPR** linexprs;
13500	   int nquadexprs;
13501	   int nbilinexprs;
13502	   int i;
13503	
13504	   assert(scip != NULL);
13505	   assert(expr != NULL);
13506	
13507	   SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
13508	
13509	   /* linear terms */
13510	   for( i = 0; i < nlinexprs; ++i )
13511	   {
13512	      assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
13513	      auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
13514	   }
13515	
13516	   /* quadratic terms */
13517	   for( i = 0; i < nquadexprs; ++i )
13518	   {
13519	      SCIP_EXPR* quadexprterm;
13520	      SCIP_Real lincoef;
13521	      SCIP_Real sqrcoef;
13522	      SCIP_Real solval;
13523	
13524	      SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
13525	
13526	      assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
13527	
13528	      solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
13529	      auxvalue += (lincoef + sqrcoef * solval) * solval;
13530	   }
13531	
13532	   /* bilinear terms */
13533	   for( i = 0; i < nbilinexprs; ++i )
13534	   {
13535	      SCIP_EXPR* expr1;
13536	      SCIP_EXPR* expr2;
13537	      SCIP_Real coef;
13538	
13539	      SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
13540	
13541	      assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
13542	      assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
13543	      auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
13544	   }
13545	
13546	   return auxvalue;
13547	}
13548	
13549	/**@addtogroup PublicNlhdlrInterfaceMethods
13550	 * @{
13551	 */
13552	
13553	/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
13554	SCIP_RETCODE SCIPincludeNlhdlrNonlinear(
13555	   SCIP*                 scip,               /**< SCIP data structure */
13556	   SCIP_NLHDLR**         nlhdlr,             /**< buffer where to store nonlinear handler */
13557	   const char*           name,               /**< name of nonlinear handler (must not be NULL) */
13558	   const char*           desc,               /**< description of nonlinear handler (can be NULL) */
13559	   int                   detectpriority,     /**< detection priority of nonlinear handler */
13560	   int                   enfopriority,       /**< enforcement priority of nonlinear handler */
13561	   SCIP_DECL_NLHDLRDETECT((*detect)),        /**< structure detection callback of nonlinear handler */
13562	   SCIP_DECL_NLHDLREVALAUX((*evalaux)),      /**< auxiliary evaluation callback of nonlinear handler */
13563	   SCIP_NLHDLRDATA*      nlhdlrdata          /**< data of nonlinear handler (can be NULL) */
13564	   )
13565	{
13566	   SCIP_CONSHDLR* conshdlr;
13567	   SCIP_CONSHDLRDATA* conshdlrdata;
13568	
13569	   assert(scip != NULL);
13570	   assert(nlhdlr != NULL);
13571	   assert(detect != NULL);
13572	
13573	   /* find myself */
13574	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13575	   if( conshdlr == NULL )
13576	   {
13577	      SCIPerrorMessage("nonlinear constraint handler not found");
13578	      return SCIP_PLUGINNOTFOUND;
13579	   }
13580	
13581	   /* create nlhdlr */
13582	   SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
13583	
13584	   /* include into constraint handler */
13585	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13586	   assert(conshdlrdata != NULL);
13587	
13588	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
13589	
13590	   conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
13591	   ++conshdlrdata->nnlhdlrs;
13592	
13593	   /* sort nonlinear handlers by detection priority, in decreasing order
13594	    * will happen in INIT, so only do when called late
13595	    */
13596	   if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
13597	      SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
13598	
13599	   return SCIP_OKAY;
13600	}
13601	
13602	/** returns a nonlinear handler of a given name (or NULL if not found) */
13603	SCIP_NLHDLR* SCIPfindNlhdlrNonlinear(
13604	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
13605	   const char*           name                /**< name of nonlinear handler */
13606	   )
13607	{
13608	   SCIP_CONSHDLRDATA* conshdlrdata;
13609	   int h;
13610	
13611	   assert(conshdlr != NULL);
13612	   assert(name != NULL);
13613	
13614	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13615	   assert(conshdlrdata != NULL);
13616	
13617	   for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
13618	      if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
13619	         return conshdlrdata->nlhdlrs[h];
13620	
13621	   return NULL;
13622	}
13623	
13624	/** gives expression data that a given nonlinear handler stored in an expression
13625	 *
13626	 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
13627	 */
13628	SCIP_NLHDLREXPRDATA* SCIPgetNlhdlrExprDataNonlinear(
13629	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
13630	   SCIP_EXPR*            expr                /**< expression */
13631	   )
13632	{
13633	   SCIP_EXPR_OWNERDATA* ownerdata;
13634	   int e;
13635	
13636	   assert(nlhdlr != NULL);
13637	   assert(expr != NULL);
13638	
13639	   ownerdata = SCIPexprGetOwnerData(expr);
13640	   assert(ownerdata != NULL);
13641	
13642	   for( e = 0; e < ownerdata->nenfos; ++e )
13643	      if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
13644	         return ownerdata->enfos[e]->nlhdlrexprdata;
13645	
13646	   return NULL;
13647	}
13648	
13649	/** @} */
13650