1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*  Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB)                      */
7    	/*                                                                           */
8    	/*  Licensed under the Apache License, Version 2.0 (the "License");          */
9    	/*  you may not use this file except in compliance with the License.         */
10   	/*  You may obtain a copy of the License at                                  */
11   	/*                                                                           */
12   	/*      http://www.apache.org/licenses/LICENSE-2.0                           */
13   	/*                                                                           */
14   	/*  Unless required by applicable law or agreed to in writing, software      */
15   	/*  distributed under the License is distributed on an "AS IS" BASIS,        */
16   	/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17   	/*  See the License for the specific language governing permissions and      */
18   	/*  limitations under the License.                                           */
19   	/*                                                                           */
20   	/*  You should have received a copy of the Apache-2.0 license                */
21   	/*  along with SCIP; see the file LICENSE. If not visit scipopt.org.         */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file   cons_nonlinear.c
26   	 * @ingroup DEFPLUGINS_CONS
27   	 * @brief  constraint handler for nonlinear constraints specified by algebraic expressions
28   	 * @author Ksenia Bestuzheva
29   	 * @author Benjamin Mueller
30   	 * @author Felipe Serrano
31   	 * @author Stefan Vigerske
32   	 */
33   	
34   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35   	
36   	#ifdef SCIP_DEBUG
37   	#define ENFO_LOGGING
38   	#endif
39   	
40   	/* enable to get log output for enforcement */
41   	/* #define ENFO_LOGGING */
42   	/* define to get enforcement logging into file */
43   	/* #define ENFOLOGFILE "consexpr_enfo.log" */
44   	
45   	/* define to get more debug output from domain propagation */
46   	/* #define DEBUG_PROP */
47   	
48   	/*lint -e440*/
49   	/*lint -e441*/
50   	/*lint -e528*/
51   	/*lint -e666*/
52   	/*lint -e777*/
53   	/*lint -e866*/
54   	
55   	#include <ctype.h>
56   	#include "scip/cons_nonlinear.h"
57   	#include "scip/nlhdlr.h"
58   	#include "scip/expr_var.h"
59   	#include "scip/expr_varidx.h"
60   	#include "scip/expr_abs.h"
61   	#include "scip/expr_sum.h"
62   	#include "scip/expr_value.h"
63   	#include "scip/expr_pow.h"
64   	#include "scip/expr_trig.h"
65   	#include "scip/nlhdlr_convex.h"
66   	#include "scip/cons_linear.h"
67   	#include "scip/cons_varbound.h"
68   	#include "scip/cons_and.h"
69   	#include "scip/cons_bounddisjunction.h"
70   	#include "scip/heur_subnlp.h"
71   	#include "scip/heur_trysol.h"
72   	#include "scip/lapack_calls.h"
73   	#include "scip/debug.h"
74   	#include "scip/dialog_default.h"
75   	#include "scip/scip_expr.h"
76   	#include "scip/symmetry_graph.h"
77   	#include "scip/prop_symmetry.h"
78   	#include "symmetry/struct_symmetry.h"
79   	#include "scip/pub_misc_sort.h"
80   	
81   	
82   	/* fundamental constraint handler properties */
83   	#define CONSHDLR_NAME          "nonlinear"
84   	#define CONSHDLR_DESC          "handler for nonlinear constraints specified by algebraic expressions"
85   	#define CONSHDLR_ENFOPRIORITY       -60 /**< priority of the constraint handler for constraint enforcing */
86   	#define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
87   	#define CONSHDLR_EAGERFREQ          100 /**< frequency for using all instead of only the useful constraints in separation,
88   	                                         *   propagation and enforcement, -1 for no eager evaluations, 0 for first only */
89   	#define CONSHDLR_NEEDSCONS         TRUE /**< should the constraint handler be skipped, if no constraints are available? */
90   	
91   	/* optional constraint handler properties */
92   	#define CONSHDLR_SEPAPRIORITY        10 /**< priority of the constraint handler for separation */
93   	#define CONSHDLR_SEPAFREQ             1 /**< frequency for separating cuts; zero means to separate only in the root node */
94   	#define CONSHDLR_DELAYSEPA        FALSE /**< should separation method be delayed, if other separators found cuts? */
95   	
96   	#define CONSHDLR_PROPFREQ             1 /**< frequency for propagating domains; zero means only preprocessing propagation */
97   	#define CONSHDLR_DELAYPROP        FALSE /**< should propagation method be delayed, if other propagators found reductions? */
98   	#define CONSHDLR_PROP_TIMING     SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
99   	
100  	#define CONSHDLR_PRESOLTIMING    SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
101  	#define CONSHDLR_MAXPREROUNDS        -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
102  	
103  	/* properties of the nonlinear constraint handler statistics table */
104  	#define TABLE_NAME_NONLINEAR           "cons_nonlinear"
105  	#define TABLE_DESC_NONLINEAR           "nonlinear constraint handler statistics"
106  	#define TABLE_POSITION_NONLINEAR       14600                  /**< the position of the statistics table */
107  	#define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
108  	
109  	/* properties of the nonlinear handler statistics table */
110  	#define TABLE_NAME_NLHDLR              "nlhdlr"
111  	#define TABLE_DESC_NLHDLR              "nonlinear handler statistics"
112  	#define TABLE_POSITION_NLHDLR          14601                  /**< the position of the statistics table */
113  	#define TABLE_EARLIEST_STAGE_NLHDLR    SCIP_STAGE_PRESOLVING  /**< output of the statistics table is only printed from this stage onwards */
114  	
115  	#define DIALOG_NAME            "nlhdlrs"
116  	#define DIALOG_DESC            "display nonlinear handlers"
117  	#define DIALOG_ISSUBMENU          FALSE
118  	
119  	#define VERTEXPOLY_MAXPERTURBATION      1e-3 /**< maximum perturbation */
120  	#define VERTEXPOLY_USEDUALSIMPLEX       TRUE /**< use dual or primal simplex algorithm? */
121  	#define VERTEXPOLY_RANDNUMINITSEED  20181029 /**< seed for random number generator, which is used to move points away from the boundary */
122  	#define VERTEXPOLY_ADJUSTFACETFACTOR     1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
123  	
124  	#define BRANCH_RANDNUMINITSEED      20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
125  	
126  	#define BILIN_MAXNAUXEXPRS                10 /**< maximal number of auxiliary expressions per bilinear term */
127  	
128  	/** translate from one value of infinity to another
129  	 *
130  	 *  if val is &ge; infty1, then give infty2, else give val
131  	 */
132  	#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
133  	
134  	/** translates x to 2^x for non-negative integer x */
135  	#define POWEROFTWO(x) (0x1u << (x))
136  	
137  	#ifdef ENFO_LOGGING
138  	#define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
139  	FILE* enfologfile = NULL;
140  	#else
141  	#define ENFOLOG(x)
142  	#endif
143  	
144  	/*
145  	 * Data structures
146  	 */
147  	
148  	/** enforcement data of an expression */
149  	typedef struct
150  	{
151  	   SCIP_NLHDLR*          nlhdlr;             /**< nonlinear handler */
152  	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata;     /**< data of nonlinear handler */
153  	   SCIP_NLHDLR_METHOD    nlhdlrparticipation;/**< methods where nonlinear handler participates */
154  	   SCIP_Bool             issepainit;         /**< was the initsepa callback of nlhdlr called */
155  	   SCIP_Real             auxvalue;           /**< auxiliary value of expression w.r.t. currently enforced solution */
156  	   SCIP_Bool             sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
157  	   SCIP_Bool             sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
158  	} EXPRENFO;
159  	
160  	/** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
161  	struct SCIP_Expr_OwnerData
162  	{
163  	   SCIP_CONSHDLR*        conshdlr;           /** nonlinear constraint handler */
164  	
165  	   /* locks and monotonicity */
166  	   int                   nlockspos;          /**< positive locks counter */
167  	   int                   nlocksneg;          /**< negative locks counter */
168  	   SCIP_MONOTONE*        monotonicity;       /**< array containing monotonicity of expression w.r.t. each child */
169  	   int                   monotonicitysize;   /**< length of monotonicity array */
170  	
171  	   /* propagation (in addition to activity that is stored in expr) */
172  	   SCIP_INTERVAL         propbounds;         /**< bounds to propagate in reverse propagation */
173  	   unsigned int          propboundstag;      /**< tag to indicate whether propbounds are valid for the current propagation rounds */
174  	   SCIP_Bool             inpropqueue;        /**< whether expression is queued for propagation */
175  	
176  	   /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
177  	   EXPRENFO**            enfos;              /**< enforcements */
178  	   int                   nenfos;             /**< number of enforcements, or -1 if not initialized */
179  	   unsigned int          lastenforced;       /**< last enforcement round where expression was enforced successfully */
180  	   unsigned int          nactivityusesprop;  /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
181  	   unsigned int          nactivityusessepa;  /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
182  	   unsigned int          nauxvaruses;        /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
183  	   SCIP_VAR*             auxvar;             /**< auxiliary variable used for outer approximation cuts */
184  	
185  	   /* branching */
186  	   SCIP_Real             violscoresum;       /**< sum of violation scores for branching stored for this expression */
187  	   SCIP_Real             violscoremax;       /**< max of violation scores for branching stored for this expression */
188  	   int                   nviolscores;        /**< number of violation scores stored for this expression */
189  	   unsigned int          violscoretag;       /**< tag to decide whether a violation score of an expression needs to be initialized */
190  	
191  	   /* additional data for variable expressions (TODO move into sub-struct?) */
192  	   SCIP_CONS**           conss;              /**< constraints in which this variable appears */
193  	   int                   nconss;             /**< current number of constraints in conss */
194  	   int                   consssize;          /**< length of conss array */
195  	   SCIP_Bool             consssorted;        /**< is the array of constraints sorted */
196  	
197  	   int                   filterpos;          /**< position of eventdata in SCIP's event filter, -1 if not catching events */
198  	};
199  	
200  	/** constraint data for nonlinear constraints */
201  	struct SCIP_ConsData
202  	{
203  	   /* data that defines the constraint: expression and sides */
204  	   SCIP_EXPR*            expr;               /**< expression that represents this constraint */
205  	   SCIP_Real             lhs;                /**< left-hand side */
206  	   SCIP_Real             rhs;                /**< right-hand side */
207  	
208  	   /* variables */
209  	   SCIP_EXPR**           varexprs;           /**< array containing all variable expressions */
210  	   int                   nvarexprs;          /**< total number of variable expressions */
211  	   SCIP_Bool             catchedevents;      /**< do we catch events on variables? */
212  	
213  	   /* constraint violation */
214  	   SCIP_Real             lhsviol;            /**< violation of left-hand side by current solution */
215  	   SCIP_Real             rhsviol;            /**< violation of right-hand side by current solution */
216  	   SCIP_Real             gradnorm;           /**< norm of gradient of constraint function in current solution (if evaluated) */
217  	   SCIP_Longint          gradnormsoltag;     /**< tag of solution used that gradnorm corresponds to */
218  	
219  	   /* status flags */
220  	   unsigned int          ispropagated:1;     /**< did we propagate the current bounds already? */
221  	   unsigned int          issimplified:1;     /**< did we simplify the expression tree already? */
222  	
223  	   /* locks */
224  	   int                   nlockspos;          /**< number of positive locks */
225  	   int                   nlocksneg;          /**< number of negative locks */
226  	
227  	   /* repair infeasible solutions */
228  	   SCIP_VAR*             linvardecr;         /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
229  	   SCIP_VAR*             linvarincr;         /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
230  	   SCIP_Real             linvardecrcoef;     /**< linear coefficient of linvardecr */
231  	   SCIP_Real             linvarincrcoef;     /**< linear coefficient of linvarincr */
232  	
233  	   /* miscellaneous */
234  	   SCIP_EXPRCURV         curv;               /**< curvature of the root expression w.r.t. the original variables */
235  	   SCIP_NLROW*           nlrow;              /**< a nonlinear row representation of this constraint */
236  	   int                   consindex;          /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
237  	};
238  	
239  	/** constraint upgrade method */
240  	typedef struct
241  	{
242  	   SCIP_DECL_NONLINCONSUPGD((*consupgd));    /**< method to call for upgrading nonlinear constraint */
243  	   int                   priority;           /**< priority of upgrading method */
244  	   SCIP_Bool             active;             /**< is upgrading enabled */
245  	} CONSUPGRADE;
246  	
247  	/** constraint handler data */
248  	struct SCIP_ConshdlrData
249  	{
250  	   /* nonlinear handler */
251  	   SCIP_NLHDLR**         nlhdlrs;            /**< nonlinear handlers */
252  	   int                   nnlhdlrs;           /**< number of nonlinear handlers */
253  	   int                   nlhdlrssize;        /**< size of nlhdlrs array */
254  	   SCIP_Bool             indetect;           /**< whether we are currently in detectNlhdlr */
255  	   SCIP_Bool             registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
256  	   SCIP_Bool             registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
257  	
258  	   /* constraint upgrades */
259  	   CONSUPGRADE**         consupgrades;       /**< constraint upgrade methods for specializing nonlinear constraints */
260  	   int                   consupgradessize;   /**< size of consupgrades array */
261  	   int                   nconsupgrades;      /**< number of constraint upgrade methods */
262  	
263  	   /* other plugins */
264  	   SCIP_EVENTHDLR*       eventhdlr;          /**< handler for variable bound change events */
265  	   SCIP_HEUR*            subnlpheur;         /**< a pointer to the subnlp heuristic, if available */
266  	   SCIP_HEUR*            trysolheur;         /**< a pointer to the trysol heuristic, if available */
267  	
268  	   /* tags and counters */
269  	   int                   auxvarid;           /**< unique id for the next auxiliary variable */
270  	   SCIP_Longint          curboundstag;       /**< tag indicating current variable bounds */
271  	   SCIP_Longint          lastboundrelax;     /**< tag when bounds where most recently relaxed */
272  	   SCIP_Longint          lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
273  	   unsigned int          enforound;          /**< total number of enforcement calls, including current one */
274  	   int                   lastconsindex;      /**< last used consindex, plus one */
275  	
276  	   /* activity intervals and domain propagation */
277  	   SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
278  	   SCIP_Bool             globalbounds;       /**< whether global variable bounds should be used for activity calculation */
279  	   SCIP_QUEUE*           reversepropqueue;   /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
280  	   SCIP_Bool             forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
281  	   unsigned int          curpropboundstag;   /**< tag indicating current propagation rounds, to match with expr->propboundstag */
282  	
283  	   /* parameters */
284  	   int                   maxproprounds;      /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
285  	   SCIP_Bool             propauxvars;        /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
286  	   char                  varboundrelax;      /**< strategy on how to relax variable bounds during bound tightening */
287  	   SCIP_Real             varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
288  	   SCIP_Real             conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
289  	   SCIP_Real             vp_maxperturb;      /**< maximal relative perturbation of reference point */
290  	   SCIP_Real             vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
291  	   SCIP_Bool             vp_dualsimplex;     /**< whether to use dual simplex instead of primal simplex for facet computing LP */
292  	   SCIP_Bool             reformbinprods;     /**< whether to reformulate products of binary variables during presolving */
293  	   SCIP_Bool             reformbinprodsand;  /**< whether to use the AND constraint handler for reformulating binary products */
294  	   int                   reformbinprodsfac;  /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
295  	   SCIP_Bool             forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
296  	   SCIP_Bool             tightenlpfeastol;   /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
297  	   SCIP_Bool             propinenforce;      /**< whether to (re)run propagation in enforcement */
298  	   SCIP_Real             weakcutthreshold;   /**< threshold for when to regard a cut from an estimator as weak */
299  	   SCIP_Real             strongcutmaxcoef;   /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
300  	   SCIP_Bool             strongcutefficacy;  /**< consider efficacy requirement when deciding whether a cut is "strong" */
301  	   SCIP_Bool             forcestrongcut;     /**< whether to force "strong" cuts in enforcement */
302  	   SCIP_Real             enfoauxviolfactor;  /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
303  	   SCIP_Real             weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
304  	   char                  rownotremovable;    /**< whether to make rows to be non-removable in the node where they are added (can prevent some cycling): 'o'ff, in 'e'nforcement only, 'a'lways */
305  	   char                  violscale;          /**< method how to scale violations to make them comparable (not used for feasibility check) */
306  	   char                  checkvarlocks;      /**< whether variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction) */
307  	   int                   branchauxmindepth;  /**< from which depth on to allow branching on auxiliary variables */
308  	   SCIP_Bool             branchexternal;     /**< whether to use external branching candidates for branching */
309  	   SCIP_Real             branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
310  	   SCIP_Real             branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
311  	   SCIP_Real             branchviolweight;   /**< weight by how much to consider the violation assigned to a variable for its branching score */
312  	   SCIP_Real             branchdualweight;   /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
313  	   SCIP_Real             branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
314  	   SCIP_Real             branchdomainweight; /**< weight by how much to consider the domain width in branching score */
315  	   SCIP_Real             branchvartypeweight;/**< weight by how much to consider variable type in branching score */
316  	   char                  branchscoreagg;     /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
317  	   char                  branchviolsplit;    /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
318  	   SCIP_Real             branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
319  	   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) */
320  	   SCIP_Bool             assumeconvex;       /**< whether to assume that any constraint is convex */
321  	
322  	   /* statistics */
323  	   SCIP_Longint          nweaksepa;          /**< number of times we used "weak" cuts for enforcement */
324  	   SCIP_Longint          ntightenlp;         /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
325  	   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 */
326  	   SCIP_Longint          ndesperatebranch;   /**< number of times we branched on some variable because normal enforcement was not successful */
327  	   SCIP_Longint          ndesperatecutoff;   /**< number of times we cut off a node in enforcement because no branching candidate could be found */
328  	   SCIP_Longint          nforcelp;           /**< number of times we forced solving the LP when enforcing a pseudo solution */
329  	   SCIP_CLOCK*           canonicalizetime;   /**< time spend for canonicalization */
330  	   SCIP_Longint          ncanonicalizecalls; /**< number of times we called canonicalization */
331  	
332  	   /* facets of envelops of vertex-polyhedral functions */
333  	   SCIP_RANDNUMGEN*      vp_randnumgen;      /**< random number generator used to perturb reference point */
334  	   SCIP_LPI*             vp_lp[SCIP_MAXVERTEXPOLYDIM+1];  /**< LPs used to compute facets for functions of different dimension */
335  	
336  	   /* hashing of bilinear terms */
337  	   SCIP_HASHTABLE*       bilinhashtable;     /**< hash table for bilinear terms */
338  	   SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
339  	   int                   nbilinterms;        /**< total number of bilinear terms */
340  	   int                   bilintermssize;     /**< size of bilinterms array */
341  	   int                   bilinmaxnauxexprs;  /**< maximal number of auxiliary expressions per bilinear term */
342  	
343  	   /* branching */
344  	   SCIP_RANDNUMGEN*      branchrandnumgen;   /**< random number generated used in branching variable selection */
345  	   char                  branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
346  	
347  	   /* misc */
348  	   SCIP_Bool             checkedvarlocks;    /**< whether variables contained in a single constraint have been already considered */
349  	   SCIP_HASHMAP*         var2expr;           /**< hashmap to map SCIP variables to variable-expressions */
350  	   int                   newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
351  	};
352  	
353  	/** branching candidate with various scores */
354  	typedef struct
355  	{
356  	   SCIP_EXPR*            expr;               /**< expression that holds branching candidate */
357  	   SCIP_Real             auxviol;            /**< aux-violation score of candidate */
358  	   SCIP_Real             domain;             /**< domain score of candidate */
359  	   SCIP_Real             dual;               /**< dual score of candidate */
360  	   SCIP_Real             pscost;             /**< pseudo-cost score of candidate */
361  	   SCIP_Real             vartype;            /**< variable type score of candidate */
362  	   SCIP_Real             weighted;           /**< weighted sum of other scores, see scoreBranchingCandidates() */
363  	} BRANCHCAND;
364  	
365  	/*
366  	 * Local methods
367  	 */
368  	
369  	/* forward declaration */
370  	static
371  	SCIP_RETCODE forwardPropExpr(
372  	   SCIP*                 scip,               /**< SCIP data structure */
373  	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
374  	   SCIP_EXPR*            rootexpr,           /**< expression */
375  	   SCIP_Bool             tightenauxvars,     /**< should the bounds of auxiliary variables be tightened? */
376  	   SCIP_Bool*            infeasible,         /**< buffer to store whether the problem is infeasible (NULL if not needed) */
377  	   int*                  ntightenings        /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
378  	   );
379  	
380  	/** frees auxiliary variables of expression, if any */
381  	static
382  	SCIP_RETCODE freeAuxVar(
383  	   SCIP*                 scip,               /**< SCIP data structure */
384  	   SCIP_EXPR*            expr                /**< expression which auxvar to free, if any */
385  	   )
386  	{
387  	   SCIP_EXPR_OWNERDATA* mydata;
388  	
389  	   assert(scip != NULL);
390  	   assert(expr != NULL);
391  	
392  	   mydata = SCIPexprGetOwnerData(expr);
393  	   assert(mydata != NULL);
394  	
395  	   if( mydata->auxvar == NULL )
396  	      return SCIP_OKAY;
397  	
398  	   SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
399  	
400  	   /* remove variable locks
401  	    * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
402  	    */
403  	   SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
404  	
405  	   /* release auxiliary variable */
406  	   SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
407  	   assert(mydata->auxvar == NULL);
408  	
409  	   return SCIP_OKAY;
410  	}
411  	
412  	/** frees data used for enforcement of expression, that is, nonlinear handlers
413  	 *
414  	 * can also clear indicators whether expr needs enforcement methods, that is,
415  	 * free an associated auxiliary variable and reset the nactivityuses counts
416  	 */
417  	static
418  	SCIP_RETCODE freeEnfoData(
419  	   SCIP*                 scip,               /**< SCIP data structure */
420  	   SCIP_EXPR*            expr,               /**< expression whose enforcement data will be released */
421  	   SCIP_Bool             freeauxvar          /**< whether aux var should be released and activity usage counts be reset */
422  	   )
423  	{
424  	   SCIP_EXPR_OWNERDATA* mydata;
425  	   int e;
426  	
427  	   mydata = SCIPexprGetOwnerData(expr);
428  	   assert(mydata != NULL);
429  	
430  	   if( freeauxvar )
431  	   {
432  	      /* free auxiliary variable */
433  	      SCIP_CALL( freeAuxVar(scip, expr) );
434  	      assert(mydata->auxvar == NULL);
435  	
436  	      /* reset count on activity and auxvar usage */
437  	      mydata->nactivityusesprop = 0;
438  	      mydata->nactivityusessepa = 0;
439  	      mydata->nauxvaruses = 0;
440  	   }
441  	
442  	   /* free data stored by nonlinear handlers */
443  	   for( e = 0; e < mydata->nenfos; ++e )
444  	   {
445  	      SCIP_NLHDLR* nlhdlr;
446  	
447  	      assert(mydata->enfos[e] != NULL);
448  	
449  	      nlhdlr = mydata->enfos[e]->nlhdlr;
450  	      assert(nlhdlr != NULL);
451  	
452  	      if( mydata->enfos[e]->issepainit )
453  	      {
454  	         /* call the separation deinitialization callback of the nonlinear handler */
455  	         SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
456  	         mydata->enfos[e]->issepainit = FALSE;
457  	      }
458  	
459  	      /* free nlhdlr exprdata, if there is any and there is a method to free this data */
460  	      if( mydata->enfos[e]->nlhdlrexprdata != NULL )
461  	      {
462  	         SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
463  	         assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
464  	      }
465  	
466  	      /* free enfo data */
467  	      SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
468  	   }
469  	
470  	   /* free array with enfo data */
471  	   SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
472  	
473  	   /* we need to look at this expression in detect again */
474  	   mydata->nenfos = -1;
475  	
476  	   return SCIP_OKAY;
477  	}
478  	
479  	/** callback that frees data that this conshdlr stored in an expression */
480  	static
481  	SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
482  	{
483  	   assert(scip != NULL);
484  	   assert(expr != NULL);
485  	   assert(ownerdata != NULL);
486  	   assert(*ownerdata != NULL);
487  	
488  	   /* expression should not be locked anymore */
489  	   assert((*ownerdata)->nlockspos == 0);
490  	   assert((*ownerdata)->nlocksneg == 0);
491  	
492  	   SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
493  	
494  	   /* expression should not be enforced anymore */
495  	   assert((*ownerdata)->nenfos <= 0);
496  	   assert((*ownerdata)->auxvar == NULL);
497  	
498  	   if( SCIPisExprVar(scip, expr) )
499  	   {
500  	      SCIP_CONSHDLRDATA* conshdlrdata;
501  	      SCIP_VAR* var;
502  	
503  	      /* there should be no constraints left that still use this variable */
504  	      assert((*ownerdata)->nconss == 0);
505  	      /* thus, there should also be no variable event catched (via this exprhdlr) */
506  	      assert((*ownerdata)->filterpos == -1);
507  	
508  	      SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
509  	
510  	      /* update var2expr hashmap in conshdlrdata */
511  	      conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
512  	      assert(conshdlrdata != NULL);
513  	
514  	      var = SCIPgetVarExprVar(expr);
515  	      assert(var != NULL);
516  	
517  	      /* remove var -> expr map from hashmap if present
518  	       *  (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
519  	       *   if variable-expression stored for var is different, then also do nothing)
520  	       */
521  	      if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
522  	      {
523  	         SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
524  	      }
525  	   }
526  	
527  	   SCIPfreeBlockMemory(scip, ownerdata);
528  	
529  	   return SCIP_OKAY;
530  	}
531  	
532  	static
533  	SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
534  	{  /*lint --e{715}*/
535  	   assert(ownerdata != NULL);
536  	
537  	   /* print nl handlers associated to expr */
538  	   if( ownerdata->nenfos > 0 )
539  	   {
540  	      int i;
541  	      SCIPinfoMessage(scip, file, "   {");
542  	
543  	      for( i = 0; i < ownerdata->nenfos; ++i )
544  	      {
545  	         SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
546  	         if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
547  	            SCIPinfoMessage(scip, file, "a");
548  	         if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
549  	            SCIPinfoMessage(scip, file, "u");
550  	         if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
551  	            SCIPinfoMessage(scip, file, "o");
552  	         if( i < ownerdata->nenfos-1 )
553  	            SCIPinfoMessage(scip, file, ", ");
554  	      }
555  	
556  	      SCIPinfoMessage(scip, file, "}");
557  	   }
558  	
559  	   /* print aux var associated to expr */
560  	   if( ownerdata->auxvar != NULL )
561  	   {
562  	      SCIPinfoMessage(scip, file, "  (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
563  	   }
564  	   SCIPinfoMessage(scip, file, "\n");
565  	
566  	   return SCIP_OKAY;
567  	}
568  	
569  	/** possibly reevaluates and then returns the activity of the expression
570  	 *
571  	 * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
572  	 */
573  	static
574  	SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
575  	{
576  	   SCIP_CONSHDLRDATA* conshdlrdata;
577  	
578  	   assert(scip != NULL);
579  	   assert(expr != NULL);
580  	   assert(ownerdata != NULL);
581  	
582  	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
583  	   assert(conshdlrdata != NULL);
584  	
585  	   if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
586  	   {
587  	      /* update activity of expression */
588  	      SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
589  	
590  	      assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
591  	   }
592  	
593  	   return SCIP_OKAY;
594  	}
595  	
596  	/** callback that creates data that this conshdlr wants to store in an expression */
597  	static
598  	SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
599  	{
600  	   assert(scip != NULL);
601  	   assert(expr != NULL);
602  	   assert(ownerdata != NULL);
603  	
604  	   SCIP_CALL( SCIPallocClearBlockMemory(scip, ownerdata) );
605  	   (*ownerdata)->nenfos = -1;
606  	   (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
607  	
608  	   if( SCIPisExprVar(scip, expr) )
609  	   {
610  	      SCIP_CONSHDLRDATA* conshdlrdata;
611  	      SCIP_VAR* var;
612  	
613  	      (*ownerdata)->filterpos = -1;
614  	
615  	      /* add to var2expr hashmap if not having expr for var yet */
616  	
617  	      conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
618  	      assert(conshdlrdata != NULL);
619  	
620  	      var = SCIPgetVarExprVar(expr);
621  	
622  	      if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
623  	      {
624  	         /* store the variable expression in the hashmap */
625  	         SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
626  	      }
627  	      else
628  	      {
629  	         /* if expr was just created, then it shouldn't already be stored as image of var */
630  	         assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
631  	      }
632  	   }
633  	   else
634  	   {
635  	      /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
636  	      (*ownerdata)->filterpos = -2;
637  	   }
638  	
639  	   *ownerfree = exprownerFree;
640  	   *ownerprint = exprownerPrint;
641  	   *ownerevalactivity = exprownerEvalactivity;
642  	
643  	   return SCIP_OKAY;
644  	}
645  	
646  	/** creates a variable expression or retrieves from hashmap in conshdlr data */
647  	static
648  	SCIP_RETCODE createExprVar(
649  	   SCIP*                 scip,               /**< SCIP data structure */
650  	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
651  	   SCIP_EXPR**           expr,               /**< pointer where to store expression */
652  	   SCIP_VAR*             var                 /**< variable to be stored */
653  	   )
654  	{
655  	   assert(conshdlr != NULL);
656  	   assert(expr != NULL);
657  	   assert(var != NULL);
658  	
659  	   /* get variable expression representing the given variable if there is one already */
660  	   *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
661  	
662  	   if( *expr == NULL )
663  	   {
664  	      /* create a new variable expression; this also captures the expression */
665  	      SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
666  	      assert(*expr != NULL);
667  	      /* exprownerCreate should have added var->expr to var2expr */
668  	      assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
669  	   }
670  	   else
671  	   {
672  	      /* only capture already existing expr to get a consistent uses-count */
673  	      SCIPcaptureExpr(*expr);
674  	   }
675  	
676  	   return SCIP_OKAY;
677  	}
678  	
679  	/* map var exprs to var-expr from var2expr hashmap */
680  	static
681  	SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
682  	{  /*lint --e{715}*/
683  	   SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
684  	
685  	   assert(sourcescip != NULL);
686  	   assert(targetscip != NULL);
687  	   assert(sourceexpr != NULL);
688  	   assert(targetexpr != NULL);
689  	   assert(*targetexpr == NULL);
690  	   assert(mapexprdata != NULL);
691  	
692  	   /* do not provide map if not variable */
693  	   if( !SCIPisExprVar(sourcescip, sourceexpr) )
694  	      return SCIP_OKAY;
695  	
696  	   SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
697  	
698  	   return SCIP_OKAY;
699  	}
700  	
701  	/* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
702  	static
703  	SCIP_DECL_EXPR_MAPEXPR(mapexprtransvar)
704  	{  /*lint --e{715}*/
705  	   SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
706  	   SCIP_VAR* var;
707  	
708  	   assert(sourcescip != NULL);
709  	   assert(targetscip != NULL);
710  	   assert(sourceexpr != NULL);
711  	   assert(targetexpr != NULL);
712  	   assert(*targetexpr == NULL);
713  	   assert(mapexprdata != NULL);
714  	
715  	   /* do not provide map if not variable */
716  	   if( !SCIPisExprVar(sourcescip, sourceexpr) )
717  	      return SCIP_OKAY;
718  	
719  	   var = SCIPgetVarExprVar(sourceexpr);
720  	   assert(var != NULL);
721  	
722  	   /* transform variable */
723  	   SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
724  	   assert(var != NULL);
725  	
726  	   SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
727  	
728  	   return SCIP_OKAY;
729  	}
730  	
731  	/** stores all variable expressions into a given constraint */
732  	static
733  	SCIP_RETCODE storeVarExprs(
734  	   SCIP*                 scip,               /**< SCIP data structure */
735  	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
736  	   SCIP_CONSDATA*        consdata            /**< constraint data */
737  	   )
738  	{
739  	   SCIP_CONSHDLRDATA* conshdlrdata;
740  	   int varexprssize;
741  	   int i;
742  	
743  	   assert(consdata != NULL);
744  	
745  	   /* skip if we have stored the variable expressions already */
746  	   if( consdata->varexprs != NULL )
747  	      return SCIP_OKAY;
748  	
749  	   assert(consdata->varexprs == NULL);
750  	   assert(consdata->nvarexprs == 0);
751  	
752  	   /* get an upper bound on number of variable expressions */
753  	   if( consdata->issimplified )
754  	   {
755  	      /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
756  	       * so we cannot have more variable expression than the number of active variables
757  	       */
758  	      varexprssize = SCIPgetNVars(scip);
759  	   }
760  	   else
761  	   {
762  	      SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
763  	   }
764  	
765  	   /* create array to store all variable expressions */
766  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
767  	
768  	   SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
769  	   assert(varexprssize >= consdata->nvarexprs);
770  	
771  	   /* shrink array if there are less variables in the expression than in the problem */
772  	   if( varexprssize > consdata->nvarexprs )
773  	   {
774  	      SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
775  	   }
776  	
777  	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
778  	   assert(conshdlrdata != NULL);
779  	   assert(conshdlrdata->var2expr != NULL);
780  	
781  	   /* ensure that for every variable an entry exists in the var2expr hashmap
782  	    * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
783  	    */
784  	   for( i = 0; i < consdata->nvarexprs; ++i )
785  	   {
786  	      if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
787  	      {
788  	         SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
789  	      }
790  	   }
791  	
792  	   return SCIP_OKAY;
793  	}
794  	
795  	/** frees all variable expression stored in storeVarExprs() */
796  	static
797  	SCIP_RETCODE freeVarExprs(
798  	   SCIP*                 scip,               /**< SCIP data structure */
799  	   SCIP_CONSDATA*        consdata            /**< constraint data */
800  	   )
801  	{
802  	   int i;
803  	
804  	   assert(consdata != NULL);
805  	
806  	   /* skip if we have stored the variable expressions already*/
807  	   if( consdata->varexprs == NULL )
808  	      return SCIP_OKAY;
809  	
810  	   assert(consdata->varexprs != NULL);
811  	   assert(consdata->nvarexprs >= 0);
812  	
813  	   /* release variable expressions */
814  	   for( i = 0; i < consdata->nvarexprs; ++i )
815  	   {
816  	      assert(consdata->varexprs[i] != NULL);
817  	      SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
818  	      assert(consdata->varexprs[i] == NULL);
819  	   }
820  	
821  	   /* free variable expressions */
822  	   SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
823  	   consdata->varexprs = NULL;
824  	   consdata->nvarexprs = 0;
825  	
826  	   return SCIP_OKAY;
827  	}
828  	
829  	/** interval evaluation of variables as used in bound tightening
830  	 *
831  	 * Returns slightly relaxed local variable bounds of a variable as interval.
832  	 * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
833  	 */
834  	static
835  	SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
836  	{
837  	   SCIP_INTERVAL interval;
838  	   SCIP_CONSHDLRDATA* conshdlrdata;
839  	   SCIP_Real lb;
840  	   SCIP_Real ub;
841  	
842  	   assert(scip != NULL);
843  	   assert(var != NULL);
844  	
845  	   conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
846  	   assert(conshdlrdata != NULL);
847  	
848  	   if( conshdlrdata->globalbounds )
849  	   {
850  	      lb = SCIPvarGetLbGlobal(var);
851  	      ub = SCIPvarGetUbGlobal(var);
852  	   }
853  	   else
854  	   {
855  	      lb = SCIPvarGetLbLocal(var);
856  	      ub = SCIPvarGetUbLocal(var);
857  	   }
858  	   assert(lb <= ub);  /* SCIP should ensure that variable bounds are not contradicting */
859  	
860  	   /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
861  	   if( SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT )
862  	   {
863  	      lb = EPSROUND(lb, 0.0); /*lint !e835*/
864  	      ub = EPSROUND(ub, 0.0); /*lint !e835*/
865  	   }
866  	
867  	   /* integer variables should always have integral bounds in SCIP */
868  	   assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var));  /*lint !e835*/
869  	   assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var));  /*lint !e835*/
870  	
871  	   switch( conshdlrdata->varboundrelax )
872  	   {
873  	      case 'n' : /* no relaxation */
874  	         break;
875  	
876  	      case 'a' : /* relax by absolute value */
877  	      {
878  	         /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
879  	         if( SCIPvarIsIntegral(var) )
880  	            break;
881  	
882  	         if( !SCIPisInfinity(scip, -lb) )
883  	         {
884  	            /* reduce lb by epsilon, or to the next integer value, which ever is larger */
885  	            SCIP_Real bnd = floor(lb);
886  	            lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
887  	         }
888  	
889  	         if( !SCIPisInfinity(scip, ub) )
890  	         {
891  	            /* increase ub by epsilon, or to the next integer value, which ever is smaller */
892  	            SCIP_Real bnd = ceil(ub);
893  	            ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
894  	         }
895  	
896  	         break;
897  	      }
898  	
899  	      case 'b' : /* relax always by absolute value */
900  	      {
901  	         /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
902  	         if( SCIPvarIsIntegral(var) )
903  	            break;
904  	
905  	         if( !SCIPisInfinity(scip, -lb) )
906  	            lb -= conshdlrdata->varboundrelaxamount;
907  	
908  	         if( !SCIPisInfinity(scip, ub) )
909  	            ub += conshdlrdata->varboundrelaxamount;
910  	
911  	         break;
912  	      }
913  	
914  	      case 'r' : /* relax by relative value */
915  	      {
916  	         /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
917  	         if( SCIPvarIsIntegral(var) )
918  	            break;
919  	
920  	         /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
921  	          * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
922  	          * further, do not relax beyond next integer value
923  	          */
924  	         if( !SCIPisInfinity(scip, -lb) )
925  	         {
926  	            SCIP_Real bnd = floor(lb);
927  	            lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
928  	         }
929  	
930  	         if( !SCIPisInfinity(scip, ub) )
931  	         {
932  	            SCIP_Real bnd = ceil(ub);
933  	            ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
934  	         }
935  	
936  	         break;
937  	      }
938  	
939  	      default :
940  	      {
941  	         SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
942  	         SCIPABORT();
943  	         break;
944  	      }
945  	   }
946  	
947  	   /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
948  	   lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
949  	   ub =  infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, ub);
950  	   assert(lb <= ub);
951  	
952  	   SCIPintervalSetBounds(&interval, lb, ub);
953  	
954  	   return interval;
955  	}
956  	
957  	/** compares two nonlinear constraints by its index
958  	 *
959  	 * Usable as compare operator in array sort functions.
960  	 */
961  	static
962  	SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
963  	{
964  	   SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
965  	   SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
966  	
967  	   assert(consdata1 != NULL);
968  	   assert(consdata2 != NULL);
969  	
970  	   return consdata1->consindex - consdata2->consindex;
971  	}
972  	
973  	/** processes variable fixing or bound change event */
974  	static
975  	SCIP_DECL_EVENTEXEC(processVarEvent)
976  	{  /*lint --e{715}*/
977  	   SCIP_EVENTTYPE eventtype;
978  	   SCIP_EXPR* expr;
979  	   SCIP_EXPR_OWNERDATA* ownerdata;
980  	   SCIP_Bool boundtightened = FALSE;
981  	
982  	   eventtype = SCIPeventGetType(event);
983  	   assert(eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_TYPECHANGED));
984  	
985  	   assert(eventdata != NULL);
986  	   expr = (SCIP_EXPR*) eventdata;
987  	   assert(SCIPisExprVar(scip, expr));
988  	
989  	   SCIPdebugMsg(scip, "  exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
990  	         SCIPvarGetName(SCIPeventGetVar(event)),
991  	         SCIPvarGetLbLocal(SCIPeventGetVar(event)), SCIPvarGetUbLocal(SCIPeventGetVar(event)),
992  	         SCIPvarGetLbGlobal(SCIPeventGetVar(event)), SCIPvarGetUbGlobal(SCIPeventGetVar(event)));
993  	
994  	   ownerdata = SCIPexprGetOwnerData(expr);
995  	   assert(ownerdata != NULL);
996  	   /* we only catch varevents for variables in constraints, so there should be constraints */
997  	   assert(ownerdata->nconss > 0);
998  	   assert(ownerdata->conss != NULL);
999  	
1000 	   if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1001 	      boundtightened = TRUE;
1002 	
1003 	   /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
1004 	    * however, if the boundchange is smaller than epsilon, such an event will be omitted
1005 	    * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
1006 	    * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
1007 	    * as a boundtightening (and usually it is, I would think)
1008 	    */
1009 	   if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1010 	      boundtightened = TRUE;
1011 	
1012 	   /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
1013 	    * because we will round the bounds and no longer consider relaxing them
1014 	    * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
1015 	    * (mainly to avoid a failing assert, see github issue #70)
1016 	    * usually, a change to implicit-integer would result in a boundchange on the variable as well, but not if the bound was already almost integral
1017 	    */
1018 	   if( (eventtype & SCIP_EVENTTYPE_TYPECHANGED) && (SCIPeventGetNewtype(event) == SCIP_VARTYPE_IMPLINT) &&
1019 	      (!EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0)) ) /*lint !e835*/
1020 	      boundtightened = TRUE;
1021 	
1022 	   /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1023 	    * - propagation can only find something new if a bound was tightened
1024 	    * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
1025 	    *   and we look at global changes (that is, we are not looking at boundchanges in probing)
1026 	    */
1027 	   if( boundtightened )
1028 	   {
1029 	      SCIP_CONSDATA* consdata;
1030 	      int c;
1031 	
1032 	      for( c = 0; c < ownerdata->nconss; ++c )
1033 	      {
1034 	         assert(ownerdata->conss[c] != NULL);
1035 	         consdata = SCIPconsGetData(ownerdata->conss[c]);
1036 	
1037 	         /* if bound tightening, then mark constraints to be propagated again
1038 	          * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1039 	          *   that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1040 	          *   the locks don't help since they are not available separately for each constraint
1041 	          */
1042 	         consdata->ispropagated = FALSE;
1043 	         SCIPdebugMsg(scip, "  marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1044 	
1045 	         /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1046 	         if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !SCIPinProbing(scip) )
1047 	         {
1048 	            consdata->issimplified = FALSE;
1049 	            SCIPdebugMsg(scip, "  marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1050 	         }
1051 	      }
1052 	   }
1053 	
1054 	   /* update curboundstag, lastboundrelax, and expr activity */
1055 	   if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
1056 	   {
1057 	      SCIP_CONSHDLRDATA* conshdlrdata;
1058 	      SCIP_INTERVAL activity;
1059 	
1060 	      conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1061 	      assert(conshdlrdata != NULL);
1062 	
1063 	      /* increase tag on bounds */
1064 	      ++conshdlrdata->curboundstag;
1065 	      assert(conshdlrdata->curboundstag > 0);
1066 	
1067 	      /* remember also if we relaxed bounds now */
1068 	      if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1069 	         conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1070 	
1071 	      /* update the activity of the var-expr here immediately
1072 	       * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1073 	       */
1074 	      SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1075 	      /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1076 	#ifdef DEBUG_PROP
1077 	      SCIPdebugMsg(scip, "  var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1078 	#endif
1079 	      SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1080 	   }
1081 	
1082 	   return SCIP_OKAY;
1083 	}
1084 	
1085 	/** registers event handler to catch variable events on variable
1086 	 *
1087 	 * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1088 	 * When an event occurs, all stored constraints are notified.
1089 	 */
1090 	static
1091 	SCIP_RETCODE catchVarEvent(
1092 	   SCIP*                 scip,               /**< SCIP data structure */
1093 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1094 	   SCIP_EXPR*            expr,               /**< variable expression */
1095 	   SCIP_CONS*            cons                /**< nonlinear constraint */
1096 	   )
1097 	{
1098 	   SCIP_EXPR_OWNERDATA* ownerdata;
1099 	
1100 	   assert(eventhdlr != NULL);
1101 	   assert(expr != NULL);
1102 	   assert(SCIPisExprVar(scip, expr));
1103 	   assert(cons != NULL);
1104 	
1105 	   ownerdata = SCIPexprGetOwnerData(expr);
1106 	   assert(ownerdata != NULL);
1107 	
1108 	#ifndef NDEBUG
1109 	   /* assert that constraint does not double-catch variable */
1110 	   {
1111 	      int i;
1112 	      for( i = 0; i < ownerdata->nconss; ++i )
1113 	         assert(ownerdata->conss[i] != cons);
1114 	   }
1115 	#endif
1116 	
1117 	   /* append cons to ownerdata->conss */
1118 	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1119 	   ownerdata->conss[ownerdata->nconss++] = cons;
1120 	   /* we're not capturing the constraint here to avoid circular references */
1121 	
1122 	   /* updated sorted flag */
1123 	   if( ownerdata->nconss <= 1 )
1124 	      ownerdata->consssorted = TRUE;
1125 	   else if( ownerdata->consssorted )
1126 	      ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1127 	
1128 	   /* catch variable events, if not done so yet (first constraint) */
1129 	   if( ownerdata->filterpos < 0 )
1130 	   {
1131 	      SCIP_EVENTTYPE eventtype;
1132 	
1133 	      assert(ownerdata->nconss == 1);
1134 	
1135 	      eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_TYPECHANGED;
1136 	
1137 	      SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1138 	      assert(ownerdata->filterpos >= 0);
1139 	   }
1140 	
1141 	   return SCIP_OKAY;
1142 	}
1143 	
1144 	/** catch variable events */
1145 	static
1146 	SCIP_RETCODE catchVarEvents(
1147 	   SCIP*                 scip,               /**< SCIP data structure */
1148 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1149 	   SCIP_CONS*            cons                /**< constraint for which to catch bound change events */
1150 	   )
1151 	{
1152 	   SCIP_CONSHDLRDATA* conshdlrdata;
1153 	   SCIP_CONSDATA* consdata;
1154 	   SCIP_EXPR* expr;
1155 	   int i;
1156 	
1157 	   assert(eventhdlr != NULL);
1158 	   assert(cons != NULL);
1159 	
1160 	   consdata = SCIPconsGetData(cons);
1161 	   assert(consdata != NULL);
1162 	   assert(consdata->varexprs != NULL);
1163 	   assert(consdata->nvarexprs >= 0);
1164 	
1165 	   /* check if we have catched variable events already */
1166 	   if( consdata->catchedevents )
1167 	      return SCIP_OKAY;
1168 	
1169 	   conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1170 	   assert(conshdlrdata != NULL);
1171 	#ifndef CR_API  /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1172 	   assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1173 	#endif
1174 	
1175 	   SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1176 	
1177 	   for( i = 0; i < consdata->nvarexprs; ++i )
1178 	   {
1179 	      expr = consdata->varexprs[i];
1180 	
1181 	      assert(expr != NULL);
1182 	      assert(SCIPisExprVar(scip, expr));
1183 	
1184 	      SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1185 	
1186 	      /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1187 	       * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1188 	       */
1189 	      if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1190 	      {
1191 	         SCIP_INTERVAL activity;
1192 	         SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1193 	         /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1194 	         SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1195 	#ifdef DEBUG_PROP
1196 	         SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1197 	#endif
1198 	      }
1199 	   }
1200 	
1201 	   consdata->catchedevents = TRUE;
1202 	
1203 	   return SCIP_OKAY;
1204 	}
1205 	
1206 	/** unregisters event handler to catch variable events on variable
1207 	 *
1208 	 * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1209 	 * If this was the last constraint, then the event handler is unregistered for this variable.
1210 	 */
1211 	static
1212 	SCIP_RETCODE dropVarEvent(
1213 	   SCIP*                 scip,               /**< SCIP data structure */
1214 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1215 	   SCIP_EXPR*            expr,               /**< variable expression */
1216 	   SCIP_CONS*            cons                /**< expr constraint */
1217 	   )
1218 	{
1219 	   SCIP_EXPR_OWNERDATA* ownerdata;
1220 	   int pos;
1221 	
1222 	   assert(eventhdlr != NULL);
1223 	   assert(expr != NULL);
1224 	   assert(SCIPisExprVar(scip, expr));
1225 	   assert(cons != NULL);
1226 	
1227 	   ownerdata = SCIPexprGetOwnerData(expr);
1228 	   assert(ownerdata != NULL);
1229 	   assert(ownerdata->nconss > 0);
1230 	
1231 	   if( ownerdata->conss[ownerdata->nconss-1] == cons )
1232 	   {
1233 	      pos = ownerdata->nconss-1;
1234 	   }
1235 	   else
1236 	   {
1237 	      if( !ownerdata->consssorted )
1238 	      {
1239 	         SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1240 	         ownerdata->consssorted = TRUE;
1241 	      }
1242 	
1243 	      if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1244 	      {
1245 	         SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1246 	         return SCIP_ERROR;
1247 	      }
1248 	      assert(pos >= 0 && pos < ownerdata->nconss);
1249 	   }
1250 	   assert(ownerdata->conss[pos] == cons);
1251 	
1252 	   /* move last constraint into position of removed constraint */
1253 	   if( pos < ownerdata->nconss-1 )
1254 	   {
1255 	      ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1256 	      ownerdata->consssorted = FALSE;
1257 	   }
1258 	   --ownerdata->nconss;
1259 	
1260 	   /* drop variable events if that was the last constraint */
1261 	   if( ownerdata->nconss == 0 )
1262 	   {
1263 	      SCIP_EVENTTYPE eventtype;
1264 	
1265 	      assert(ownerdata->filterpos >= 0);
1266 	
1267 	      eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_TYPECHANGED;
1268 	
1269 	      SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1270 	      ownerdata->filterpos = -1;
1271 	   }
1272 	
1273 	   return SCIP_OKAY;
1274 	}
1275 	
1276 	/** drop variable events */
1277 	static
1278 	SCIP_RETCODE dropVarEvents(
1279 	   SCIP*                 scip,               /**< SCIP data structure */
1280 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1281 	   SCIP_CONS*            cons                /**< constraint for which to drop bound change events */
1282 	   )
1283 	{
1284 	   SCIP_CONSDATA* consdata;
1285 	   int i;
1286 	
1287 	   assert(eventhdlr != NULL);
1288 	   assert(cons != NULL);
1289 	
1290 	   consdata = SCIPconsGetData(cons);
1291 	   assert(consdata != NULL);
1292 	
1293 	   /* check if we have catched variable events already */
1294 	   if( !consdata->catchedevents )
1295 	      return SCIP_OKAY;
1296 	
1297 	   assert(consdata->varexprs != NULL);
1298 	   assert(consdata->nvarexprs >= 0);
1299 	
1300 	   SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1301 	
1302 	   for( i = consdata->nvarexprs - 1; i >= 0; --i )
1303 	   {
1304 	      assert(consdata->varexprs[i] != NULL);
1305 	
1306 	      SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1307 	   }
1308 	
1309 	   consdata->catchedevents = FALSE;
1310 	
1311 	   return SCIP_OKAY;
1312 	}
1313 	
1314 	/** creates and captures a nonlinear constraint
1315 	 *
1316 	 * @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
1317 	 */
1318 	static
1319 	SCIP_RETCODE createCons(
1320 	   SCIP*                 scip,               /**< SCIP data structure */
1321 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1322 	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
1323 	   const char*           name,               /**< name of constraint */
1324 	   SCIP_EXPR*            expr,               /**< expression of constraint (must not be NULL) */
1325 	   SCIP_Real             lhs,                /**< left hand side of constraint */
1326 	   SCIP_Real             rhs,                /**< right hand side of constraint */
1327 	   SCIP_Bool             copyexpr,           /**< whether to copy the expression or reuse the given expr (capture it) */
1328 	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
1329 	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1330 	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
1331 	                                              *   Usually set to TRUE. */
1332 	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
1333 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
1334 	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
1335 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
1336 	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
1337 	                                              *   Usually set to TRUE. */
1338 	   SCIP_Bool             local,              /**< is constraint only valid locally?
1339 	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1340 	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
1341 	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
1342 	                                              *   adds coefficients to this constraint. */
1343 	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
1344 	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
1345 	                                              *   are separated as constraints. */
1346 	   SCIP_Bool             removable           /**< should the relaxation be removed from the LP due to aging or cleanup?
1347 	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1348 	   )
1349 	{
1350 	   SCIP_CONSHDLRDATA* conshdlrdata;
1351 	   SCIP_CONSDATA* consdata;
1352 	
1353 	   assert(conshdlr != NULL);
1354 	   assert(expr != NULL);
1355 	
1356 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1357 	   assert(conshdlrdata != NULL);
1358 	
1359 	   if( local && SCIPgetDepth(scip) != 0 )
1360 	   {
1361 	      SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1362 	      return SCIP_INVALIDCALL;
1363 	   }
1364 	
1365 	   /* TODO we should allow for non-initial nonlinear constraints */
1366 	   if( !initial )
1367 	   {
1368 	      SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1369 	      return SCIP_INVALIDCALL;
1370 	   }
1371 	
1372 	   /* create constraint data */
1373 	   SCIP_CALL( SCIPallocClearBlockMemory(scip, &consdata) );
1374 	
1375 	   if( copyexpr )
1376 	   {
1377 	      /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1378 	      SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1379 	   }
1380 	   else
1381 	   {
1382 	      consdata->expr = expr;
1383 	      SCIPcaptureExpr(consdata->expr);
1384 	   }
1385 	   consdata->lhs = lhs;
1386 	   consdata->rhs = rhs;
1387 	   consdata->consindex = conshdlrdata->lastconsindex++;
1388 	   consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1389 	
1390 	   /* create constraint */
1391 	   SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1392 	         local, modifiable, dynamic, removable, FALSE) );
1393 	
1394 	   return SCIP_OKAY;
1395 	}
1396 	
1397 	/** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1398 	 *
1399 	 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1400 	 * Assume that f(x) is associated with auxiliary variable z.
1401 	 *
1402 	 * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1403 	 * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1404 	 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1405 	 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1406 	 *
1407 	 * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1408 	 */
1409 	static
1410 	SCIP_Real getExprAbsOrigViolation(
1411 	   SCIP*                 scip,               /**< SCIP data structure */
1412 	   SCIP_EXPR*            expr,               /**< expression */
1413 	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
1414 	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(x) is violated, or NULL */
1415 	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(x) is violated, or NULL */
1416 	   )
1417 	{
1418 	   SCIP_EXPR_OWNERDATA* ownerdata;
1419 	   SCIP_Real auxvarvalue;
1420 	
1421 	   assert(expr != NULL);
1422 	
1423 	   ownerdata = SCIPexprGetOwnerData(expr);
1424 	   assert(ownerdata != NULL);
1425 	   assert(ownerdata->auxvar != NULL);
1426 	
1427 	   if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1428 	   {
1429 	      if( violunder != NULL )
1430 	         *violunder = TRUE;
1431 	      if( violover != NULL )
1432 	         *violover = TRUE;
1433 	      return SCIPinfinity(scip);
1434 	   }
1435 	
1436 	   auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1437 	
1438 	   if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1439 	   {
1440 	      if( violunder != NULL )
1441 	         *violunder = FALSE;
1442 	      if( violover != NULL )
1443 	         *violover = TRUE;
1444 	      return auxvarvalue - SCIPexprGetEvalValue(expr);
1445 	   }
1446 	
1447 	   if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1448 	   {
1449 	      if( violunder != NULL )
1450 	         *violunder = TRUE;
1451 	      if( violover != NULL )
1452 	         *violover = FALSE;
1453 	      return SCIPexprGetEvalValue(expr) - auxvarvalue;
1454 	   }
1455 	
1456 	   if( violunder != NULL )
1457 	      *violunder = FALSE;
1458 	   if( violover != NULL )
1459 	      *violover = FALSE;
1460 	   return 0.0;
1461 	}
1462 	
1463 	/** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1464 	 *
1465 	 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1466 	 * Assume that f(w) is associated with auxiliary variable z.
1467 	 *
1468 	 * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1469 	 * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1470 	 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1471 	 * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1472 	 *
1473 	 * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1474 	 */
1475 	static
1476 	SCIP_Real getExprAbsAuxViolation(
1477 	   SCIP*                 scip,               /**< SCIP data structure */
1478 	   SCIP_EXPR*            expr,               /**< expression */
1479 	   SCIP_Real             auxvalue,           /**< value of f(w) */
1480 	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
1481 	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(w) is violated, or NULL */
1482 	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(w) is violated, or NULL */
1483 	   )
1484 	{
1485 	   SCIP_EXPR_OWNERDATA* ownerdata;
1486 	   SCIP_Real auxvarvalue;
1487 	
1488 	   assert(expr != NULL);
1489 	
1490 	   ownerdata = SCIPexprGetOwnerData(expr);
1491 	   assert(ownerdata != NULL);
1492 	   assert(ownerdata->auxvar != NULL);
1493 	
1494 	   if( auxvalue == SCIP_INVALID )
1495 	   {
1496 	      if( violunder != NULL )
1497 	         *violunder = TRUE;
1498 	      if( violover != NULL )
1499 	         *violover = TRUE;
1500 	      return SCIPinfinity(scip);
1501 	   }
1502 	
1503 	   auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1504 	
1505 	   if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1506 	   {
1507 	      if( violunder != NULL )
1508 	         *violunder = FALSE;
1509 	      if( violover != NULL )
1510 	         *violover = TRUE;
1511 	      return auxvarvalue - auxvalue;
1512 	   }
1513 	
1514 	   if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1515 	   {
1516 	      if( violunder != NULL )
1517 	         *violunder = TRUE;
1518 	      if( violover != NULL )
1519 	         *violover = FALSE;
1520 	      return auxvalue - auxvarvalue;
1521 	   }
1522 	
1523 	   if( violunder != NULL )
1524 	      *violunder = FALSE;
1525 	   if( violover != NULL )
1526 	      *violover = FALSE;
1527 	
1528 	   return 0.0;
1529 	}
1530 	
1531 	/** computes violation of a constraint */
1532 	static
1533 	SCIP_RETCODE computeViolation(
1534 	   SCIP*                 scip,               /**< SCIP data structure */
1535 	   SCIP_CONS*            cons,               /**< constraint */
1536 	   SCIP_SOL*             sol,                /**< solution or NULL if LP solution should be used */
1537 	   SCIP_Longint          soltag              /**< tag that uniquely identifies the solution (with its values), or 0. */
1538 	   )
1539 	{
1540 	   SCIP_CONSDATA* consdata;
1541 	   SCIP_Real activity;
1542 	
1543 	   assert(scip != NULL);
1544 	   assert(cons != NULL);
1545 	
1546 	   consdata = SCIPconsGetData(cons);
1547 	   assert(consdata != NULL);
1548 	
1549 	   SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1550 	   activity = SCIPexprGetEvalValue(consdata->expr);
1551 	
1552 	   /* consider constraint as violated if it is undefined in the current point */
1553 	   if( activity == SCIP_INVALID )
1554 	   {
1555 	      consdata->lhsviol = SCIPinfinity(scip);
1556 	      consdata->rhsviol = SCIPinfinity(scip);
1557 	      return SCIP_OKAY;
1558 	   }
1559 	
1560 	   /* compute violations */
1561 	   consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs  - activity;
1562 	   consdata->rhsviol = SCIPisInfinity(scip,  consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1563 	
1564 	   return SCIP_OKAY;
1565 	}
1566 	
1567 	/** returns absolute violation of a constraint
1568 	 *
1569 	 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1570 	 */
1571 	static
1572 	SCIP_Real getConsAbsViolation(
1573 	   SCIP_CONS*            cons                /**< constraint */
1574 	   )
1575 	{
1576 	   SCIP_CONSDATA* consdata;
1577 	
1578 	   assert(cons != NULL);
1579 	
1580 	   consdata = SCIPconsGetData(cons);
1581 	   assert(consdata != NULL);
1582 	
1583 	   return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1584 	}
1585 	
1586 	/** computes relative violation of a constraint
1587 	 *
1588 	 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1589 	 */
1590 	static
1591 	SCIP_RETCODE getConsRelViolation(
1592 	   SCIP*                 scip,               /**< SCIP data structure */
1593 	   SCIP_CONS*            cons,               /**< constraint */
1594 	   SCIP_Real*            viol,               /**< buffer to store violation */
1595 	   SCIP_SOL*             sol,                /**< solution or NULL if LP solution should be used */
1596 	   SCIP_Longint          soltag              /**< tag that uniquely identifies the solution (with its values), or 0 */
1597 	   )
1598 	{
1599 	   SCIP_CONSHDLR* conshdlr;
1600 	   SCIP_CONSHDLRDATA* conshdlrdata;
1601 	   SCIP_CONSDATA* consdata;
1602 	   SCIP_Real scale;
1603 	
1604 	   assert(cons != NULL);
1605 	   assert(viol != NULL);
1606 	
1607 	   conshdlr = SCIPconsGetHdlr(cons);
1608 	   assert(conshdlr != NULL);
1609 	
1610 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1611 	   assert(conshdlrdata != NULL);
1612 	
1613 	   *viol = getConsAbsViolation(cons);
1614 	
1615 	   if( conshdlrdata->violscale == 'n' )
1616 	      return SCIP_OKAY;
1617 	
1618 	   if( SCIPisInfinity(scip, *viol) )
1619 	      return SCIP_OKAY;
1620 	
1621 	   consdata = SCIPconsGetData(cons);
1622 	   assert(consdata != NULL);
1623 	
1624 	   if( conshdlrdata->violscale == 'a' )
1625 	   {
1626 	      scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1627 	
1628 	      /* consider value of side that is violated for scaling, too */
1629 	      if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1630 	      {
1631 	         assert(!SCIPisInfinity(scip, -consdata->lhs));
1632 	         scale = REALABS(consdata->lhs);
1633 	      }
1634 	      else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1635 	      {
1636 	         assert(!SCIPisInfinity(scip,  consdata->rhs));
1637 	         scale = REALABS(consdata->rhs);
1638 	      }
1639 	
1640 	      *viol /= scale;
1641 	      return SCIP_OKAY;
1642 	   }
1643 	
1644 	   /* if not 'n' or 'a', then it has to be 'g' at the moment */
1645 	   assert(conshdlrdata->violscale == 'g');
1646 	   if( soltag == 0L || consdata->gradnormsoltag != soltag )
1647 	   {
1648 	      /* we need the varexprs to conveniently access the gradient */
1649 	      SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1650 	
1651 	      /* update cached value of norm of gradient */
1652 	      consdata->gradnorm = 0.0;
1653 	
1654 	      /* compute gradient */
1655 	      SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1656 	
1657 	      /* gradient evaluation error -> no scaling */
1658 	      if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1659 	      {
1660 	         int i;
1661 	         for( i = 0; i < consdata->nvarexprs; ++i )
1662 	         {
1663 	            SCIP_Real deriv;
1664 	
1665 	            assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1666 	            deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1667 	            if( deriv == SCIP_INVALID )
1668 	            {
1669 	               /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1670 	               consdata->gradnorm = 0.0;
1671 	               break;
1672 	            }
1673 	
1674 	            consdata->gradnorm += deriv*deriv;
1675 	         }
1676 	      }
1677 	      consdata->gradnorm = sqrt(consdata->gradnorm);
1678 	      consdata->gradnormsoltag = soltag;
1679 	   }
1680 	
1681 	   *viol /= MAX(1.0, consdata->gradnorm);
1682 	
1683 	   return SCIP_OKAY;
1684 	}
1685 	
1686 	/** returns whether constraint is currently violated
1687 	 *
1688 	 * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1689 	 */
1690 	static
1691 	SCIP_Bool isConsViolated(
1692 	   SCIP*                 scip,               /**< SCIP data structure */
1693 	   SCIP_CONS*            cons                /**< constraint */
1694 	   )
1695 	{
1696 	   return getConsAbsViolation(cons) > SCIPfeastol(scip);
1697 	}
1698 	
1699 	/** checks for a linear variable that can be increased or decreased without harming feasibility */
1700 	static
1701 	void findUnlockedLinearVar(
1702 	   SCIP*                 scip,               /**< SCIP data structure */
1703 	   SCIP_CONS*            cons                /**< constraint */
1704 	   )
1705 	{
1706 	   SCIP_CONSDATA* consdata;
1707 	   int poslock;
1708 	   int neglock;
1709 	   int i;
1710 	
1711 	   assert(cons != NULL);
1712 	
1713 	   consdata = SCIPconsGetData(cons);
1714 	   assert(consdata != NULL);
1715 	
1716 	   consdata->linvarincr = NULL;
1717 	   consdata->linvardecr = NULL;
1718 	   consdata->linvarincrcoef = 0.0;
1719 	   consdata->linvardecrcoef = 0.0;
1720 	
1721 	   /* root expression is not a sum -> no unlocked linear variable available */
1722 	   if( !SCIPisExprSum(scip, consdata->expr) )
1723 	      return;
1724 	
1725 	   for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1726 	   {
1727 	      SCIP_EXPR* child;
1728 	
1729 	      child = SCIPexprGetChildren(consdata->expr)[i];
1730 	      assert(child != NULL);
1731 	
1732 	      /* check whether the child is a variable expression */
1733 	      if( SCIPisExprVar(scip, child) )
1734 	      {
1735 	         SCIP_VAR* var = SCIPgetVarExprVar(child);
1736 	         SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1737 	
1738 	         if( coef > 0.0 )
1739 	         {
1740 	            poslock = !SCIPisInfinity(scip,  consdata->rhs) ? 1 : 0;
1741 	            neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1742 	         }
1743 	         else
1744 	         {
1745 	            poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1746 	            neglock = !SCIPisInfinity(scip,  consdata->rhs) ? 1 : 0;
1747 	         }
1748 	         SCIPdebugMsg(scip, "child <%s> locks: %d %d\n", SCIPvarGetName(var), SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL), SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL));
1749 	
1750 	         if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1751 	         {
1752 	            /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1753 	             * if we have already one candidate, then take the one where the loss in the objective function is less
1754 	             */
1755 	            if( (consdata->linvardecr == NULL) ||
1756 	               (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1757 	            {
1758 	               consdata->linvardecr = var;
1759 	               consdata->linvardecrcoef = coef;
1760 	            }
1761 	         }
1762 	
1763 	         if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1764 	         {
1765 	            /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1766 	             * if we have already one candidate, then take the one where the loss in the objective function is less
1767 	             */
1768 	            if( (consdata->linvarincr == NULL) ||
1769 	               (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1770 	            {
1771 	               consdata->linvarincr = var;
1772 	               consdata->linvarincrcoef = coef;
1773 	            }
1774 	         }
1775 	      }
1776 	   }
1777 	
1778 	   assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1779 	   assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1780 	
1781 	   if( consdata->linvarincr != NULL )
1782 	   {
1783 	      SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1784 	   }
1785 	   if( consdata->linvardecr != NULL )
1786 	   {
1787 	      SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1788 	   }
1789 	}
1790 	
1791 	/** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1792 	 *  moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1793 	 *
1794 	 *  The method assumes that this is always possible and that not all constraints are feasible already.
1795 	 */
1796 	static
1797 	SCIP_RETCODE proposeFeasibleSolution(
1798 	   SCIP*                 scip,               /**< SCIP data structure */
1799 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1800 	   SCIP_CONS**           conss,              /**< constraints to process */
1801 	   int                   nconss,             /**< number of constraints */
1802 	   SCIP_SOL*             sol,                /**< solution to process */
1803 	   SCIP_Bool*            success             /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1804 	   )
1805 	{
1806 	   SCIP_CONSHDLRDATA* conshdlrdata;
1807 	   SCIP_SOL* newsol;
1808 	   int c;
1809 	
1810 	   assert(scip  != NULL);
1811 	   assert(conshdlr != NULL);
1812 	   assert(conss != NULL || nconss == 0);
1813 	   assert(success != NULL);
1814 	
1815 	   *success = FALSE;
1816 	
1817 	   /* don't propose new solutions if not in presolve or solving */
1818 	   if( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE || SCIPgetStage(scip) >= SCIP_STAGE_SOLVED )
1819 	      return SCIP_OKAY;
1820 	
1821 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1822 	   assert(conshdlrdata != NULL);
1823 	
1824 	   if( sol != NULL )
1825 	   {
1826 	      SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1827 	   }
1828 	   else
1829 	   {
1830 	      SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1831 	   }
1832 	   SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1833 	   SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1834 	      sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1835 	
1836 	   for( c = 0; c < nconss; ++c )
1837 	   {
1838 	      SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
1839 	      SCIP_Real viol = 0.0;
1840 	      SCIP_Real delta;
1841 	      SCIP_Real gap;
1842 	
1843 	      assert(consdata != NULL);
1844 	
1845 	      /* get absolute violation and sign */
1846 	      if( consdata->lhsviol > SCIPfeastol(scip) )
1847 	         viol = consdata->lhsviol; /* lhs - activity */
1848 	      else if( consdata->rhsviol > SCIPfeastol(scip) )
1849 	         viol = -consdata->rhsviol; /* rhs - activity */
1850 	      else
1851 	         continue; /* constraint is satisfied */
1852 	
1853 	      if( consdata->linvarincr != NULL &&
1854 	         ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1855 	      {
1856 	         SCIP_VAR* var = consdata->linvarincr;
1857 	
1858 	         /* compute how much we would like to increase var */
1859 	         delta = viol / consdata->linvarincrcoef;
1860 	         assert(delta > 0.0);
1861 	
1862 	         /* if var has an upper bound, may need to reduce delta */
1863 	         if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1864 	         {
1865 	            gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1866 	            delta = MIN(MAX(0.0, gap), delta);
1867 	         }
1868 	         if( SCIPisPositive(scip, delta) )
1869 	         {
1870 	            /* if variable is integral, round delta up so that it will still have an integer value */
1871 	            if( SCIPvarIsIntegral(var) )
1872 	               delta = SCIPceil(scip, delta);
1873 	
1874 	            SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1875 	            SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1876 	               SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));  /*lint !e613*/
1877 	
1878 	            /* adjust constraint violation, if satisfied go on to next constraint */
1879 	            viol -= consdata->linvarincrcoef * delta;
1880 	            if( SCIPisZero(scip, viol) )
1881 	               continue;
1882 	         }
1883 	      }
1884 	
1885 	      assert(viol != 0.0);
1886 	      if( consdata->linvardecr != NULL &&
1887 	         ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1888 	      {
1889 	         SCIP_VAR* var = consdata->linvardecr;
1890 	
1891 	         /* compute how much we would like to decrease var */
1892 	         delta = viol / consdata->linvardecrcoef;
1893 	         assert(delta < 0.0);
1894 	
1895 	         /* if var has a lower bound, may need to reduce delta */
1896 	         if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
1897 	         {
1898 	            gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1899 	            delta = MAX(MIN(0.0, gap), delta);
1900 	         }
1901 	         if( SCIPisNegative(scip, delta) )
1902 	         {
1903 	            /* if variable is integral, round delta down so that it will still have an integer value */
1904 	            if( SCIPvarIsIntegral(var) )
1905 	               delta = SCIPfloor(scip, delta);
1906 	            SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1907 	            /*lint --e{613} */
1908 	            SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1909 	               SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1910 	
1911 	            /* adjust constraint violation, if satisfied go on to next constraint */
1912 	            viol -= consdata->linvardecrcoef * delta;
1913 	            if( SCIPisZero(scip, viol) )
1914 	               continue;
1915 	         }
1916 	      }
1917 	
1918 	      /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1919 	      break;
1920 	   }
1921 	
1922 	   /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1923 	    * then pass it to the trysol heuristic
1924 	    */
1925 	   if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1926 	   {
1927 	      SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1928 	
1929 	      assert(conshdlrdata->trysolheur != NULL);
1930 	      SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1931 	
1932 	      *success = TRUE;
1933 	   }
1934 	
1935 	   SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1936 	
1937 	   return SCIP_OKAY;
1938 	}
1939 	
1940 	/** notify nonlinear handlers to add linearization in new solution that has been found
1941 	 *
1942 	 * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1943 	 *
1944 	 * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1945 	 * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1946 	 * cut that is valid and supporting in the given solution.
1947 	 * For example, for convex constraints, we achieve this by linearizing.
1948 	 * For SOC, we also linearize, but on a a convex reformulation.
1949 	 *
1950 	 * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1951 	 * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1952 	 */
1953 	static
1954 	SCIP_RETCODE notifyNlhdlrNewsol(
1955 	   SCIP*                 scip,               /**< SCIP data structure */
1956 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
1957 	   SCIP_CONS**           conss,              /**< constraints */
1958 	   int                   nconss,             /**< number of constraints */
1959 	   SCIP_SOL*             sol,                /**< reference point where to estimate */
1960 	   SCIP_Bool             solisbest           /**< whether solution is best */
1961 	   )
1962 	{
1963 	   SCIP_CONSDATA* consdata;
1964 	   SCIP_Longint soltag;
1965 	   SCIP_EXPRITER* it;
1966 	   SCIP_EXPR* expr;
1967 	   int c, e;
1968 	
1969 	   assert(scip != NULL);
1970 	   assert(conshdlr != NULL);
1971 	   assert(conss != NULL || nconss == 0);
1972 	
1973 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1974 	
1975 	   /* TODO probably we just evaluated all expressions when checking the sol before it was added
1976 	    * would be nice to recognize this and skip reevaluating
1977 	    */
1978 	   soltag = SCIPgetExprNewSoltag(scip);
1979 	
1980 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
1981 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
1982 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_LEAVEEXPR);
1983 	
1984 	   for( c = 0; c < nconss; ++c )
1985 	   {
1986 	      /* skip constraints that are not enabled or deleted or have separation disabled */
1987 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
1988 	         continue;
1989 	      assert(SCIPconsIsActive(conss[c]));
1990 	
1991 	      consdata = SCIPconsGetData(conss[c]);
1992 	      assert(consdata != NULL);
1993 	
1994 	      ENFOLOG(
1995 	      {
1996 	         int i;
1997 	         SCIPinfoMessage(scip, enfologfile, " constraint ");
1998 	         SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
1999 	         SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2000 	         for( i = 0; i < consdata->nvarexprs; ++i )
2001 	         {
2002 	            SCIP_VAR* var;
2003 	            var = SCIPgetVarExprVar(consdata->varexprs[i]);
2004 	            SCIPinfoMessage(scip, enfologfile, "  %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2005 	                  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2006 	         }
2007 	      })
2008 	
2009 	      SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2010 	      assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2011 	
2012 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2013 	      {
2014 	         SCIP_EXPR_OWNERDATA* ownerdata;
2015 	
2016 	         ownerdata = SCIPexprGetOwnerData(expr);
2017 	         assert(ownerdata != NULL);
2018 	
2019 	         /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2020 	         assert(SCIPexprGetEvalTag(expr) == soltag);
2021 	         assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2022 	         if( ownerdata->auxvar != NULL )
2023 	         {
2024 	            SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2025 	         }
2026 	
2027 	         /* let nonlinear handler generate cuts by calling the sollinearize callback */
2028 	         for( e = 0; e < ownerdata->nenfos; ++e )
2029 	         {
2030 	            /* call sollinearize callback, if implemented by nlhdlr */
2031 	            SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
2032 	               ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
2033 	               ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
2034 	               ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
2035 	         }
2036 	      }
2037 	   }
2038 	
2039 	   SCIPfreeExpriter(&it);
2040 	
2041 	   return SCIP_OKAY;
2042 	}
2043 	
2044 	/** processes the event that a new primal solution has been found */
2045 	static
2046 	SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2047 	{
2048 	   SCIP_CONSHDLR* conshdlr;
2049 	   SCIP_CONSHDLRDATA* conshdlrdata;
2050 	   SCIP_SOL* sol;
2051 	
2052 	   assert(scip != NULL);
2053 	   assert(event != NULL);
2054 	   assert(eventdata != NULL);
2055 	   assert(eventhdlr != NULL);
2056 	   assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND);
2057 	
2058 	   conshdlr = (SCIP_CONSHDLR*)eventdata;
2059 	
2060 	   if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2061 	      return SCIP_OKAY;
2062 	
2063 	   sol = SCIPeventGetSol(event);
2064 	   assert(sol != NULL);
2065 	
2066 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2067 	   assert(conshdlrdata != NULL);
2068 	
2069 	   /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2070 	    * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2071 	    * from the tree, but postprocessed via proposeFeasibleSolution
2072 	    */
2073 	   if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2074 	      return SCIP_OKAY;
2075 	
2076 	   SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2077 	
2078 	   SCIP_CALL( notifyNlhdlrNewsol(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol, (SCIPeventGetType(event) & SCIP_EVENTTYPE_BESTSOLFOUND) != 0) );
2079 	
2080 	   return SCIP_OKAY;
2081 	}
2082 	
2083 	/** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2084 	 *
2085 	 *  The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2086 	 *  tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2087 	 *
2088 	 *  Nothing will happen if SCIP is not in presolve or solve.
2089 	 */
2090 	static
2091 	SCIP_RETCODE tightenAuxVarBounds(
2092 	   SCIP*                 scip,               /**< SCIP data structure */
2093 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2094 	   SCIP_EXPR*            expr,               /**< expression whose auxvar is to be tightened */
2095 	   SCIP_INTERVAL         bounds,             /**< bounds to be used for tightening (must not be empty) */
2096 	   SCIP_Bool*            cutoff,             /**< buffer to store whether a cutoff was detected */
2097 	   int*                  ntightenings        /**< buffer to add the total number of tightenings, or NULL */
2098 	   )
2099 	{
2100 	   SCIP_VAR* var;
2101 	   SCIP_Bool tightenedlb;
2102 	   SCIP_Bool tightenedub;
2103 	   SCIP_Bool force;
2104 	
2105 	   assert(scip != NULL);
2106 	   assert(conshdlr != NULL);
2107 	   assert(expr != NULL);
2108 	   assert(cutoff != NULL);
2109 	
2110 	   /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2111 	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, bounds));
2112 	
2113 	   *cutoff = FALSE;
2114 	
2115 	   /* do not tighten variable in problem stage (important for unittests)
2116 	    * TODO put some kind of #ifdef UNITTEST around this
2117 	    */
(1) Event cond_at_most: Condition "scip->set->stage < SCIP_STAGE_INITPRESOLVE", taking true branch. Now the value of "scip->set->stage" is at most 3.
(2) Event at_most: At condition "scip->set->stage > SCIP_STAGE_SOLVING", the value of "scip->set->stage" must be at most 3.
(3) Event dead_error_condition: The condition "scip->set->stage > SCIP_STAGE_SOLVING" cannot be true.
Also see events: [dead_error_line]
2118 	   if( SCIPgetStage(scip) < SCIP_STAGE_INITPRESOLVE && SCIPgetStage(scip) > SCIP_STAGE_SOLVING )
(4) Event dead_error_line: Execution cannot reach this statement: "return SCIP_OKAY;".
Also see events: [cond_at_most][at_most][dead_error_condition]
2119 	      return SCIP_OKAY;
2120 	
2121 	   var = SCIPgetExprAuxVarNonlinear(expr);
2122 	   if( var == NULL )
2123 	      return SCIP_OKAY;
2124 	
2125 	   /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2126 	   force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2127 	
2128 	   /* try to tighten lower bound of (auxiliary) variable */
2129 	   SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2130 	   if( tightenedlb )
2131 	   {
2132 	      if( ntightenings != NULL )
2133 	         ++*ntightenings;
2134 	      SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2135 	   }
2136 	   if( *cutoff )
2137 	   {
2138 	      SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2139 	      return SCIP_OKAY;
2140 	   }
2141 	
2142 	   /* try to tighten upper bound of (auxiliary) variable */
2143 	   SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2144 	   if( tightenedub )
2145 	   {
2146 	      if( ntightenings != NULL )
2147 	         ++*ntightenings;
2148 	      SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2149 	   }
2150 	   if( *cutoff )
2151 	   {
2152 	      SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2153 	      return SCIP_OKAY;
2154 	   }
2155 	
2156 	   /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2157 	    * that seems unnecessary and we could easily undo this here, e.g.,
2158 	    * if( tightenedlb ) expr->activity.inf = bounds.inf
2159 	    */
2160 	
2161 	   return SCIP_OKAY;
2162 	}
2163 	
2164 	/** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2165 	 *  and tries to tighten the bounds of the auxiliary variables accordingly
2166 	 */
2167 	static
2168 	SCIP_RETCODE forwardPropExpr(
2169 	   SCIP*                 scip,               /**< SCIP data structure */
2170 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2171 	   SCIP_EXPR*            rootexpr,           /**< expression */
2172 	   SCIP_Bool             tightenauxvars,     /**< should the bounds of auxiliary variables be tightened? */
2173 	   SCIP_Bool*            infeasible,         /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2174 	   int*                  ntightenings        /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2175 	   )
2176 	{
2177 	   SCIP_EXPRITER* it;
2178 	   SCIP_EXPR* expr;
2179 	   SCIP_EXPR_OWNERDATA* ownerdata;
2180 	   SCIP_CONSHDLRDATA* conshdlrdata;
2181 	
2182 	   assert(scip != NULL);
2183 	   assert(rootexpr != NULL);
2184 	
2185 	   if( infeasible != NULL )
2186 	      *infeasible = FALSE;
2187 	   if( ntightenings != NULL )
2188 	      *ntightenings = 0;
2189 	
2190 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2191 	   assert(conshdlrdata != NULL);
2192 	
2193 	   /* if value is valid and empty, then we cannot improve, so do nothing */
2194 	   if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2195 	   {
2196 	      SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2197 	
2198 	      if( infeasible != NULL )
2199 	         *infeasible = TRUE;
2200 	
2201 	      /* just update tag to curboundstag */
2202 	      SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2203 	
2204 	      return SCIP_OKAY;
2205 	   }
2206 	
2207 	   /* if value is up-to-date, then nothing to do */
2208 	   if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2209 	   {
2210 	      SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2211 	
2212 	      assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2213 	
2214 	      return SCIP_OKAY;
2215 	   }
2216 	
2217 	   ownerdata = SCIPexprGetOwnerData(rootexpr);
2218 	   assert(ownerdata != NULL);
2219 	
2220 	   /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2221 	    * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2222 	    * during detect, we are in some in-between state where we may want to eval activity
2223 	    * on exprs that we did not notify about their activity usage
2224 	    */
2225 	   if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2226 	   {
2227 	#ifdef DEBUG_PROP
2228 	      SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2229 	#endif
2230 	      SCIPABORT();
2231 	      return SCIP_OKAY;
2232 	   }
2233 	
2234 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2235 	   SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2236 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
2237 	
2238 	   for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it);  )
2239 	   {
2240 	      switch( SCIPexpriterGetStageDFS(it) )
2241 	      {
2242 	         case SCIP_EXPRITER_VISITINGCHILD :
2243 	         {
2244 	            /* skip child if it has been evaluated already */
2245 	            SCIP_EXPR* child;
2246 	
2247 	            child = SCIPexpriterGetChildExprDFS(it);
2248 	            if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2249 	            {
2250 	               if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2251 	                  *infeasible = TRUE;
2252 	
2253 	               expr = SCIPexpriterSkipDFS(it);
2254 	               continue;
2255 	            }
2256 	
2257 	            break;
2258 	         }
2259 	
2260 	         case SCIP_EXPRITER_LEAVEEXPR :
2261 	         {
2262 	            SCIP_INTERVAL activity;
2263 	
2264 	            /* we should not have entered this expression if its activity was already up to date */
2265 	            assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2266 	
2267 	            ownerdata = SCIPexprGetOwnerData(expr);
2268 	            assert(ownerdata != NULL);
2269 	
2270 	            /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2271 	             * so we can assume that the activity is up to date for all these variables
2272 	             * UNLESS we changed the method used to evaluate activity of variable expressions
2273 	             *   or we currently use global bounds (varevents are catched for local bound changes only)
2274 	             */
2275 	            if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2276 	                SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2277 	            {
2278 	#ifndef NDEBUG
2279 	               SCIP_INTERVAL exprhdlrinterval;
2280 	
2281 	               SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2282 	               assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2283 	               assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2284 	#endif
2285 	#ifdef DEBUG_PROP
2286 	               SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2287 	#endif
2288 	               SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2289 	
2290 	               break;
2291 	            }
2292 	
2293 	            if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2294 	            {
2295 	               /* start with entire activity if current one is invalid */
2296 	               SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
2297 	            }
2298 	            else if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)) )
2299 	            {
2300 	               /* If already empty, then don't try to compute even better activity.
2301 	                * If cons_nonlinear were alone, then we should have noted that we are infeasible
2302 	                * so an assert(infeasible == NULL || *infeasible) should work here.
2303 	                * However, after reporting a cutoff due to expr->activity being empty,
2304 	                * SCIP may wander to a different node and call propagation again.
2305 	                * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2306 	                * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2307 	                * we will still have expr->activity being empty, but will have forgotten
2308 	                * that we found infeasibility here before (!2221#note_134120).
2309 	                * Therefore we just set *infeasibility=TRUE here and stop.
2310 	                */
2311 	               if( infeasible != NULL )
2312 	                  *infeasible = TRUE;
2313 	               SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2314 	               break;
2315 	            }
2316 	            else
2317 	            {
2318 	               /* start with current activity, since it is valid */
2319 	               activity = SCIPexprGetActivity(expr);
2320 	            }
2321 	
2322 	            /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2323 	            if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2324 	            {
2325 	#ifdef DEBUG_PROP
2326 	               SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2327 	#endif
2328 	               break;
2329 	            }
2330 	
2331 	#ifdef DEBUG_PROP
2332 	            SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2333 	            SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2334 	            SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2335 	#endif
2336 	
2337 	            /* run interval eval of nonlinear handlers or expression handler */
2338 	            if( ownerdata->nenfos > 0 )
2339 	            {
2340 	               SCIP_NLHDLR* nlhdlr;
2341 	               SCIP_INTERVAL nlhdlrinterval;
2342 	               int e;
2343 	
2344 	               /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2345 	               for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2346 	               {
2347 	                  /* skip nlhdlr if it does not want to participate in activity computation */
2348 	                  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2349 	                     continue;
2350 	
2351 	                  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2352 	                  assert(nlhdlr != NULL);
2353 	
2354 	                  /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2355 	                  if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2356 	                     continue;
2357 	
2358 	                  /* let nlhdlr evaluate current expression */
2359 	                  nlhdlrinterval = activity;
2360 	                  SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2361 	                     &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2362 	#ifdef DEBUG_PROP
2363 	                  SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2364 	#endif
2365 	
2366 	                  /* update activity by intersecting with computed activity */
2367 	                  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2368 	#ifdef DEBUG_PROP
2369 	                  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2370 	#endif
2371 	               }
2372 	            }
2373 	            else
2374 	            {
2375 	               /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2376 	               SCIP_INTERVAL exprhdlrinterval = activity;
2377 	               SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2378 	#ifdef DEBUG_PROP
2379 	               SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2380 	#endif
2381 	
2382 	               /* update expr->activity by intersecting with computed activity */
2383 	               SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2384 	#ifdef DEBUG_PROP
2385 	               SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2386 	#endif
2387 	            }
2388 	
2389 	            /* if expression is integral, then we try to tighten the interval bounds a bit
2390 	             * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2391 	             * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2392 	             * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2393 	             * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2394 	             * (constants should be ok, too)
2395 	             */
2396 	            if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2397 	            {
2398 	               if( activity.inf > -SCIP_INTERVAL_INFINITY )
2399 	                  activity.inf = SCIPceil(scip, activity.inf);
2400 	               if( activity.sup <  SCIP_INTERVAL_INFINITY )
2401 	                  activity.sup = SCIPfloor(scip, activity.sup);
2402 	#ifdef DEBUG_PROP
2403 	               SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2404 	#endif
2405 	            }
2406 	
2407 	            /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2408 	             * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2409 	             */
2410 	            if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2411 	            {
2412 	               SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2413 	               SCIPintervalSetEmpty(&activity);
2414 	            }
2415 	
2416 	            /* now finally store activity in expr */
2417 	            SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2418 	
2419 	            if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity) )
2420 	            {
2421 	               if( infeasible != NULL )
2422 	                  *infeasible = TRUE;
2423 	            }
2424 	            else if( tightenauxvars && ownerdata->auxvar != NULL )
2425 	            {
2426 	               SCIP_Bool tighteninfeasible;
2427 	
2428 	               SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2429 	               if( tighteninfeasible )
2430 	               {
2431 	                  if( infeasible != NULL )
2432 	                     *infeasible = TRUE;
2433 	                  SCIPintervalSetEmpty(&activity);
2434 	                  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2435 	               }
2436 	            }
2437 	
2438 	            break;
2439 	         }
2440 	
2441 	         default:
2442 	            /* you should never be here */
2443 	            SCIPerrorMessage("unexpected iterator stage\n");
2444 	            SCIPABORT();
2445 	            break;
2446 	      }
2447 	
2448 	      expr = SCIPexpriterGetNext(it);
2449 	   }
2450 	
2451 	   SCIPfreeExpriter(&it);
2452 	
2453 	   return SCIP_OKAY;
2454 	}
2455 	
2456 	/** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2457 	 *
2458 	 * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2459 	 *
2460 	 * If `subsetsufficient` is FALSE, then we require
2461 	 *  - a change from an unbounded interval to a bounded one, or
2462 	 *  - or a change from an unfixed (width > epsilon) to a fixed interval, or
2463 	 *  - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2464 	 */
2465 	static
2466 	SCIP_Bool isIntervalBetter(
2467 	   SCIP*                 scip,               /**< SCIP data structure */
2468 	   SCIP_Bool             subsetsufficient,   /**< whether the intersection being a proper subset of oldinterval is sufficient */
2469 	   SCIP_INTERVAL         newinterval,        /**< new interval */
2470 	   SCIP_INTERVAL         oldinterval         /**< old interval */
2471 	   )
2472 	{
2473 	   assert(scip != NULL);
2474 	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2475 	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2476 	
2477 	   if( subsetsufficient )
2478 	      /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2479 	      return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2480 	
2481 	   /* check whether lower bound of interval becomes finite */
2482 	   if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2483 	      return TRUE;
2484 	
2485 	   /* check whether upper bound of interval becomes finite */
2486 	   if( oldinterval.sup >=  SCIP_INTERVAL_INFINITY && newinterval.sup >  SCIP_INTERVAL_INFINITY )
2487 	      return TRUE;
2488 	
2489 	   /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2490 	   if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2491 	      return TRUE;
2492 	
2493 	   /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2494 	   if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2495 	      return TRUE;
2496 	
2497 	   /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2498 	   if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2499 	      return TRUE;
2500 	
2501 	   return FALSE;
2502 	}
2503 	
2504 	/** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2505 	 *
2506 	 *  The expression will be traversed in breadth first search by using this queue.
2507 	 *
2508 	 *  @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2509 	 *  forwardPropExpr() before calling this function.
2510 	 *
2511 	 *  @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2512 	 */
2513 	static
2514 	SCIP_RETCODE reversePropQueue(
2515 	   SCIP*                 scip,               /**< SCIP data structure */
2516 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2517 	   SCIP_Bool*            infeasible,         /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2518 	   int*                  ntightenings        /**< buffer to store the number of (variable) tightenings */
2519 	   )
2520 	{
2521 	   SCIP_CONSHDLRDATA* conshdlrdata;
2522 	   SCIP_EXPR* expr;
2523 	   SCIP_EXPR_OWNERDATA* ownerdata;
2524 	
2525 	   assert(infeasible != NULL);
2526 	   assert(ntightenings != NULL);
2527 	
2528 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2529 	   assert(conshdlrdata != NULL);
2530 	
2531 	   *ntightenings = 0;
2532 	
2533 	   /* main loop that calls reverse propagation for expressions on the queue
2534 	    * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2535 	    */
2536 	   while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2537 	   {
2538 	      SCIP_INTERVAL propbounds;
2539 	      int e;
2540 	
2541 	      expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2542 	      assert(expr != NULL);
2543 	
2544 	      ownerdata = SCIPexprGetOwnerData(expr);
2545 	      assert(ownerdata != NULL);
2546 	
2547 	      assert(ownerdata->inpropqueue);
2548 	      /* mark that the expression is not in the queue anymore */
2549 	      ownerdata->inpropqueue = FALSE;
2550 	
2551 	      /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2552 	       * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2553 	       */
2554 	      assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2555 	      assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2556 	      assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2557 	
2558 	      /* this intersects propbounds with activity and auxvar bounds
2559 	       * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2560 	       * auxvar bounds separately, so disabling this for now
2561 	       */
2562 	#ifdef SCIP_DISABLED_CODE
2563 	      propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2564 	      if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, propbounds) )
2565 	      {
2566 	         *infeasible = TRUE;
2567 	         break;
2568 	      }
2569 	#else
2570 	      propbounds = ownerdata->propbounds;
2571 	#endif
2572 	
2573 	      if( ownerdata->nenfos > 0 )
2574 	      {
2575 	         /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2576 	         for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2577 	         {
2578 	            SCIP_NLHDLR* nlhdlr;
2579 	            int nreds;
2580 	
2581 	            /* skip nlhdlr if it does not want to participate in activity computation */
2582 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2583 	               continue;
2584 	
2585 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
2586 	            assert(nlhdlr != NULL);
2587 	
2588 	            /* call the reverseprop of the nlhdlr */
2589 	#ifdef SCIP_DEBUG
2590 	            SCIPdebugMsg(scip, "call reverse propagation for ");
2591 	            SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2592 	            SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2593 	#endif
2594 	
2595 	            nreds = 0;
2596 	            SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2597 	            assert(nreds >= 0);
2598 	            *ntightenings += nreds;
2599 	         }
2600 	      }
2601 	      else if( SCIPexprhdlrHasReverseProp(SCIPexprGetHdlr(expr)) )
2602 	      {
2603 	         /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2604 	         SCIP_INTERVAL* childrenbounds;
2605 	         int c;
2606 	
2607 	#ifdef SCIP_DEBUG
2608 	         SCIPdebugMsg(scip, "call reverse propagation for ");
2609 	         SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2610 	         SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2611 	#endif
2612 	
2613 	         /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2614 	          * been initialized in detectNlhdlr yet (nenfos < 0)
2615 	          */
2616 	         assert(ownerdata->nenfos < 0);
2617 	
2618 	         SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2619 	         for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2620 	            childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2621 	
2622 	         /* call the reverseprop of the exprhdlr */
2623 	         SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2624 	
2625 	         if( !*infeasible )
2626 	            for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2627 	            {
2628 	               SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2629 	            }
2630 	
2631 	         SCIPfreeBufferArray(scip, &childrenbounds);
2632 	      }
2633 	   }
2634 	
2635 	   /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2636 	   while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2637 	   {
2638 	      expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2639 	      assert(expr != NULL);
2640 	
2641 	      ownerdata = SCIPexprGetOwnerData(expr);
2642 	      assert(ownerdata != NULL);
2643 	
2644 	      /* mark that the expression is not in the queue anymore */
2645 	      ownerdata->inpropqueue = FALSE;
2646 	   }
2647 	
2648 	   return SCIP_OKAY;
2649 	}
2650 	
2651 	/** calls domain propagation for a given set of constraints
2652 	 *
2653 	 *  The algorithm alternates calls of forward and reverse propagation.
2654 	 *  Forward propagation ensures that activity of expressions is up to date.
2655 	 *  Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2656 	 *  [lhs,rhs] interval as starting point.
2657 	 *
2658 	 *  The propagation algorithm works as follows:
2659 	 *   1. apply forward propagation (update activities) for all constraints not marked as propagated
2660 	 *   2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2661 	 *      if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2662 	 *      provide tighter bounds
2663 	 *   3. apply reverse propagation to all collected expressions; don't explore
2664 	 *      sub-expressions which have not changed since the beginning of the propagation loop
2665 	 *   4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2666 	 *
2667 	 *  @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2668 	 *  reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2669 	 *  constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2670 	 *
2671 	 *  TODO should we distinguish between expressions where activity information is used for separation and those where not,
2672 	 *    e.g., try less to propagate on convex constraints?
2673 	 */
2674 	static
2675 	SCIP_RETCODE propConss(
2676 	   SCIP*                 scip,               /**< SCIP data structure */
2677 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2678 	   SCIP_CONS**           conss,              /**< constraints to propagate */
2679 	   int                   nconss,             /**< total number of constraints */
2680 	   SCIP_Bool             force,              /**< force tightening even if below bound strengthening tolerance */
2681 	   SCIP_RESULT*          result,             /**< pointer to store the result */
2682 	   int*                  nchgbds             /**< buffer to add the number of changed bounds */
2683 	   )
2684 	{
2685 	   SCIP_CONSHDLRDATA* conshdlrdata;
2686 	   SCIP_CONSDATA* consdata;
2687 	   SCIP_EXPR_OWNERDATA* ownerdata;
2688 	   SCIP_Bool cutoff = FALSE;
2689 	   SCIP_INTERVAL conssides;
2690 	   int ntightenings;
2691 	   int roundnr;
2692 	   SCIP_EXPRITER* revpropcollectit = NULL;
2693 	   int i;
2694 	
2695 	   assert(scip != NULL);
2696 	   assert(conshdlr != NULL);
2697 	   assert(conss != NULL);
2698 	   assert(nconss >= 0);
2699 	   assert(result != NULL);
2700 	   assert(nchgbds != NULL);
2701 	   assert(*nchgbds >= 0);
2702 	
2703 	   /* no constraints to propagate */
2704 	   if( nconss == 0 )
2705 	   {
2706 	      *result = SCIP_DIDNOTRUN;
2707 	      return SCIP_OKAY;
2708 	   }
2709 	
2710 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2711 	   assert(conshdlrdata != NULL);
2712 	#ifndef CR_API  /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2713 	   assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2714 	#endif
2715 	   assert(!conshdlrdata->globalbounds);
2716 	
2717 	   *result = SCIP_DIDNOTFIND;
2718 	   roundnr = 0;
2719 	
2720 	   /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2721 	   conshdlrdata->forceboundtightening = force;
2722 	
2723 	   /* invalidate all propbounds (probably not needed) */
2724 	   ++conshdlrdata->curpropboundstag;
2725 	
2726 	   /* create iterator that we will use if we need to look at all auxvars */
2727 	   if( conshdlrdata->propauxvars )
2728 	   {
2729 	      SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2730 	   }
2731 	
2732 	   /* main propagation loop */
2733 	   do
2734 	   {
2735 	      SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2736 	
2737 	      assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2738 	
2739 	      /* apply forward propagation (update expression activities)
2740 	       * and add promising root expressions into queue for reversepropagation
2741 	       */
2742 	      for( i = 0; i < nconss; ++i )
2743 	      {
2744 	         consdata = SCIPconsGetData(conss[i]);
2745 	         assert(consdata != NULL);
2746 	
2747 	         /* skip deleted, non-active, or propagation-disabled constraints */
2748 	         if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2749 	            continue;
2750 	
2751 	         /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2752 	          * activity didn't change
2753 	          */
2754 	         if( consdata->ispropagated )
2755 	            continue;
2756 	
2757 	         /* update activities in expression */
2758 	         SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2759 	         SCIPdebugPrintCons(scip, conss[i], NULL);
2760 	
2761 	         ntightenings = 0;
2762 	         SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2763 	         assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2764 	
2765 	         if( cutoff )
2766 	         {
2767 	            SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2768 	            *result = SCIP_CUTOFF;
2769 	            break;
2770 	         }
2771 	
2772 	         ownerdata = SCIPexprGetOwnerData(consdata->expr);
2773 	
2774 	         /* 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 */
2775 	         if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2776 	         {
2777 	            /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2778 	             *   (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2779 	             *   so taking auxvar bounds is enough)
2780 	             */
2781 	            if( ownerdata->auxvar == NULL )
2782 	            {
2783 	               /* relax sides by SCIPepsilon() and handle infinite sides */
2784 	               SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2785 	               SCIP_Real rhs = SCIPisInfinity(scip,  consdata->rhs) ?  SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2786 	               SCIPintervalSetBounds(&conssides, lhs, rhs);
2787 	            }
2788 	            else
2789 	            {
2790 	               conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2791 	            }
2792 	            SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2793 	         }
2794 	         else
2795 	         {
2796 	            /* check whether bounds of any auxvar used in constraint provides a tightening
2797 	             *   (for the root expression, bounds of auxvar are initially set to constraint sides)
2798 	             * but skip exprs that have an auxvar, but do not participate in propagation
2799 	             */
2800 	            SCIP_EXPR* expr;
2801 	
2802 	            assert(revpropcollectit != NULL);
2803 	            SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2804 	            for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2805 	            {
2806 	               ownerdata = SCIPexprGetOwnerData(expr);
2807 	               assert(ownerdata != NULL);
2808 	
2809 	               if( ownerdata->auxvar == NULL )
2810 	                  continue;
2811 	
2812 	               if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2813 	                  continue;
2814 	
2815 	               conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2816 	               SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2817 	            }
2818 	         }
2819 	
2820 	         if( cutoff )
2821 	         {
2822 	            SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2823 	            *result = SCIP_CUTOFF;
2824 	            break;
2825 	         }
2826 	
2827 	         assert(ntightenings >= 0);
2828 	         if( ntightenings > 0 )
2829 	         {
2830 	            *nchgbds += ntightenings;
2831 	            *result = SCIP_REDUCEDDOM;
2832 	         }
2833 	
2834 	         /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2835 	         consdata->ispropagated = TRUE;
2836 	      }
2837 	
2838 	      /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2839 	      SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2840 	      assert(ntightenings >= 0);
2841 	      assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2842 	
2843 	      if( cutoff )
2844 	      {
2845 	         SCIPdebugMsg(scip, " -> cutoff\n");
2846 	         *result = SCIP_CUTOFF;
2847 	         break;
2848 	      }
2849 	
2850 	      if( ntightenings > 0 )
2851 	      {
2852 	         *nchgbds += ntightenings;
2853 	         *result = SCIP_REDUCEDDOM;
2854 	      }
2855 	   }
2856 	   while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2857 	
2858 	   if( conshdlrdata->propauxvars )
2859 	   {
2860 	      SCIPfreeExpriter(&revpropcollectit);
2861 	   }
2862 	
2863 	   conshdlrdata->forceboundtightening = FALSE;
2864 	
2865 	   /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2866 	   ++conshdlrdata->curpropboundstag;
2867 	
2868 	   return SCIP_OKAY;
2869 	}
2870 	
2871 	/** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2872 	 *
2873 	 * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2874 	 *
2875 	 * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2876 	 * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2877 	 */
2878 	static
2879 	SCIP_RETCODE propExprDomains(
2880 	   SCIP*                 scip,               /**< SCIP data structure */
2881 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
2882 	   SCIP_CONS**           conss,              /**< constraints to propagate */
2883 	   int                   nconss,             /**< total number of constraints */
2884 	   SCIP_RESULT*          result,             /**< pointer to store the result */
2885 	   int*                  nchgbds             /**< buffer to add the number of changed bounds */
2886 	   )
2887 	{
2888 	   SCIP_CONSDATA* consdata;
2889 	   SCIP_EXPRITER* it;
2890 	   SCIP_EXPR* expr;
2891 	   SCIP_EXPR_OWNERDATA* ownerdata;
2892 	   SCIP_Bool cutoff = FALSE;
2893 	   int ntightenings;
2894 	   int c;
2895 	   int e;
2896 	
2897 	   assert(scip != NULL);
2898 	   assert(conshdlr != NULL);
2899 	   assert(conss != NULL);
2900 	   assert(nconss >= 0);
2901 	   assert(result != NULL);
2902 	   assert(nchgbds != NULL);
2903 	   assert(*nchgbds >= 0);
2904 	
2905 	#ifndef CR_API  /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2906 	   assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
2907 	#endif
2908 	   assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
2909 	   assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
2910 	
2911 	   *result = SCIP_DIDNOTFIND;
2912 	
2913 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2914 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
2915 	
2916 	   for( c = 0; c < nconss && !cutoff; ++c )
2917 	   {
2918 	      /* skip deleted, non-active, or propagation-disabled constraints */
2919 	      if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2920 	         continue;
2921 	
2922 	      consdata = SCIPconsGetData(conss[c]);
2923 	      assert(consdata != NULL);
2924 	
2925 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2926 	      {
2927 	         ownerdata = SCIPexprGetOwnerData(expr);
2928 	         assert(ownerdata != NULL);
2929 	
2930 	         /* call reverseprop for those nlhdlr that participate in this expr's activity computation
2931 	          * this will propagate the current activity
2932 	          */
2933 	         for( e = 0; e < ownerdata->nenfos; ++e )
2934 	         {
2935 	            SCIP_NLHDLR* nlhdlr;
2936 	            assert(ownerdata->enfos[e] != NULL);
2937 	
2938 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
2939 	            assert(nlhdlr != NULL);
2940 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2941 	               continue;
2942 	
2943 	            SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2944 	                  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2945 	            ntightenings = 0;
2946 	            SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2947 	                    SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
2948 	
2949 	            if( cutoff )
2950 	            {
2951 	               /* stop everything if we detected infeasibility */
2952 	               SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
2953 	               *result = SCIP_CUTOFF;
2954 	               break;
2955 	            }
2956 	
2957 	            assert(ntightenings >= 0);
2958 	            if( ntightenings > 0 )
2959 	            {
2960 	               *nchgbds += ntightenings;
2961 	               *result = SCIP_REDUCEDDOM;
2962 	            }
2963 	         }
2964 	      }
2965 	   }
2966 	
2967 	   /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2968 	   SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2969 	   assert(ntightenings >= 0);
2970 	
2971 	   if( cutoff )
2972 	   {
2973 	      SCIPdebugMsg(scip, " -> cutoff\n");
2974 	      *result = SCIP_CUTOFF;
2975 	   }
2976 	   else if( ntightenings > 0 )
2977 	   {
2978 	      *nchgbds += ntightenings;
2979 	      *result = SCIP_REDUCEDDOM;
2980 	   }
2981 	
2982 	   SCIPfreeExpriter(&it);
2983 	
2984 	   /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2985 	   ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
2986 	
2987 	   return SCIP_OKAY;
2988 	}
2989 	
2990 	/** propagates variable locks through expression and adds locks to variables */
2991 	static
2992 	SCIP_RETCODE propagateLocks(
2993 	   SCIP*                 scip,               /**< SCIP data structure */
2994 	   SCIP_EXPR*            expr,               /**< expression */
2995 	   int                   nlockspos,          /**< number of positive locks */
2996 	   int                   nlocksneg           /**< number of negative locks */
2997 	   )
2998 	{
2999 	   SCIP_EXPR_OWNERDATA* ownerdata;
3000 	   SCIP_EXPRITER* it;
3001 	   SCIP_EXPRITER_USERDATA ituserdata;
3002 	
3003 	   assert(expr != NULL);
3004 	
3005 	   /* if no locks, then nothing to propagate */
3006 	   if( nlockspos == 0 && nlocksneg == 0 )
3007 	      return SCIP_OKAY;
3008 	
3009 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3010 	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
3011 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
3012 	   assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3013 	
3014 	   /* store locks in root node */
3015 	   ituserdata.intvals[0] = nlockspos;
3016 	   ituserdata.intvals[1] = nlocksneg;
3017 	   SCIPexpriterSetCurrentUserData(it, ituserdata);
3018 	
3019 	   while( !SCIPexpriterIsEnd(it) )
3020 	   {
3021 	      /* collect locks */
3022 	      ituserdata = SCIPexpriterGetCurrentUserData(it);
3023 	      nlockspos = ituserdata.intvals[0];
3024 	      nlocksneg = ituserdata.intvals[1];
3025 	
3026 	      ownerdata = SCIPexprGetOwnerData(expr);
3027 	
3028 	      switch( SCIPexpriterGetStageDFS(it) )
3029 	      {
3030 	         case SCIP_EXPRITER_ENTEREXPR:
3031 	         {
3032 	            if( SCIPisExprVar(scip, expr) )
3033 	            {
3034 	               /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3035 	               SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3036 	            }
3037 	
3038 	            /* add locks to expression */
3039 	            ownerdata->nlockspos += nlockspos;
3040 	            ownerdata->nlocksneg += nlocksneg;
3041 	
3042 	            /* add monotonicity information if expression has been locked for the first time */
3043 	            if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3044 	               && SCIPexprhdlrHasMonotonicity(SCIPexprGetHdlr(expr)) )
3045 	            {
3046 	               int i;
3047 	
3048 	               assert(ownerdata->monotonicity == NULL);
3049 	               assert(ownerdata->monotonicitysize == 0);
3050 	
3051 	               SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3052 	               ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3053 	
3054 	               /* store the monotonicity for each child */
3055 	               for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3056 	               {
3057 	                  SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3058 	               }
3059 	            }
3060 	            break;
3061 	         }
3062 	
3063 	         case SCIP_EXPRITER_LEAVEEXPR :
3064 	         {
3065 	            /* remove monotonicity information if expression has been unlocked */
3066 	            if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3067 	            {
3068 	               assert(ownerdata->monotonicitysize > 0);
3069 	               /* keep this assert for checking whether someone changed an expression without updating locks properly */
3070 	               assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3071 	
3072 	               SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3073 	               ownerdata->monotonicitysize = 0;
3074 	            }
3075 	            break;
3076 	         }
3077 	
3078 	         case SCIP_EXPRITER_VISITINGCHILD :
3079 	         {
3080 	            SCIP_MONOTONE monotonicity;
3081 	
3082 	            /* get monotonicity of child */
3083 	            /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3084 	             * SCIPcallExprMonotonicity
3085 	             */
3086 	            monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3087 	
3088 	            /* compute resulting locks of the child expression */
3089 	            switch( monotonicity )
3090 	            {
3091 	               case SCIP_MONOTONE_INC:
3092 	                  ituserdata.intvals[0] = nlockspos;
3093 	                  ituserdata.intvals[1] = nlocksneg;
3094 	                  break;
3095 	               case SCIP_MONOTONE_DEC:
3096 	                  ituserdata.intvals[0] = nlocksneg;
3097 	                  ituserdata.intvals[1] = nlockspos;
3098 	                  break;
3099 	               case SCIP_MONOTONE_UNKNOWN:
3100 	                  ituserdata.intvals[0] = nlockspos + nlocksneg;
3101 	                  ituserdata.intvals[1] = nlockspos + nlocksneg;
3102 	                  break;
3103 	               case SCIP_MONOTONE_CONST:
3104 	                  ituserdata.intvals[0] = 0;
3105 	                  ituserdata.intvals[1] = 0;
3106 	                  break;
3107 	            }
3108 	            /* set locks in child expression */
3109 	            SCIPexpriterSetChildUserData(it, ituserdata);
3110 	
3111 	            break;
3112 	         }
3113 	
3114 	         default :
3115 	            /* you should never be here */
3116 	            SCIPABORT();
3117 	            break;
3118 	      }
3119 	
3120 	      expr = SCIPexpriterGetNext(it);
3121 	   }
3122 	
3123 	   SCIPfreeExpriter(&it);
3124 	
3125 	   return SCIP_OKAY;
3126 	}
3127 	
3128 	/** main function for adding locks to expressions and variables
3129 	 *
3130 	 * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3131 	 * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3132 	 * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3133 	 * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3134 	 * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3135 	 * the computed monotonicity information of each expression until all locks of an expression have been removed,
3136 	 * which implies that updating the monotonicity information during the next locking of this expression does not
3137 	 * break existing locks.
3138 	 *
3139 	 * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3140 	 *       locks from an expression and repropagating them after the structural changes have been applied.
3141 	 *       Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3142 	 *       to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3143 	 */
3144 	static
3145 	SCIP_RETCODE addLocks(
3146 	   SCIP*                 scip,               /**< SCIP data structure */
3147 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
3148 	   int                   nlockspos,          /**< number of positive rounding locks */
3149 	   int                   nlocksneg           /**< number of negative rounding locks */
3150 	   )
3151 	{
3152 	   SCIP_CONSDATA* consdata;
3153 	
3154 	   assert(cons != NULL);
3155 	
3156 	   if( nlockspos == 0 && nlocksneg == 0 )
3157 	      return SCIP_OKAY;
3158 	
3159 	   consdata = SCIPconsGetData(cons);
3160 	   assert(consdata != NULL);
3161 	
3162 	   /* no constraint sides -> nothing to lock */
3163 	   if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3164 	      return SCIP_OKAY;
3165 	
3166 	   /* remember locks */
3167 	   consdata->nlockspos += nlockspos;
3168 	   consdata->nlocksneg += nlocksneg;
3169 	
3170 	   assert(consdata->nlockspos >= 0);
3171 	   assert(consdata->nlocksneg >= 0);
3172 	
3173 	   /* compute locks for lock propagation */
3174 	   if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3175 	   {
3176 	      SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3177 	   }
3178 	   else if( !SCIPisInfinity(scip, consdata->rhs) )
3179 	   {
3180 	      SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3181 	   }
3182 	   else
3183 	   {
3184 	      assert(!SCIPisInfinity(scip, -consdata->lhs));
3185 	      SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3186 	   }
3187 	
3188 	   return SCIP_OKAY;
3189 	}
3190 	
3191 	/** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3192 	static
3193 	SCIP_RETCODE createNlRow(
3194 	   SCIP*                 scip,               /**< SCIP data structure */
3195 	   SCIP_CONS*            cons                /**< nonlinear constraint */
3196 	   )
3197 	{
3198 	   SCIP_CONSDATA* consdata;
3199 	
3200 	   assert(scip != NULL);
3201 	   assert(cons != NULL);
3202 	
3203 	   consdata = SCIPconsGetData(cons);
3204 	   assert(consdata != NULL);
3205 	   assert(consdata->expr != NULL);
3206 	
3207 	   if( consdata->nlrow != NULL )
3208 	   {
3209 	      SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3210 	   }
3211 	
3212 	   /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3213 	   SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3214 	         0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3215 	
3216 	   if( SCIPisExprSum(scip, consdata->expr) )
3217 	   {
3218 	      /* if root is a sum, then split into linear and nonlinear terms */
3219 	      SCIP_EXPR* nonlinpart;
3220 	      SCIP_EXPR* child;
3221 	      SCIP_Real* coefs;
3222 	      int i;
3223 	
3224 	      coefs = SCIPgetCoefsExprSum(consdata->expr);
3225 	
3226 	      /* constant term of sum */
3227 	      SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3228 	
3229 	      /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3230 	      SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3231 	
3232 	      for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3233 	      {
3234 	         child = SCIPexprGetChildren(consdata->expr)[i];
3235 	         if( SCIPisExprVar(scip, child) )
3236 	         {
3237 	            /* linear term */
3238 	            SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3239 	         }
3240 	         else
3241 	         {
3242 	            /* nonlinear term */
3243 	            SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3244 	         }
3245 	      }
3246 	
3247 	      if( SCIPexprGetNChildren(nonlinpart) > 0 )
3248 	      {
3249 	         /* add expression to nlrow (this will make a copy) */
3250 	         SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3251 	      }
3252 	      SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3253 	   }
3254 	   else
3255 	   {
3256 	      SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3257 	   }
3258 	
3259 	   return SCIP_OKAY;
3260 	}
3261 	
3262 	/** compares enfodata by enforcement priority of nonlinear handler
3263 	 *
3264 	 * If handlers have same enforcement priority, then compare by detection priority, then by name.
3265 	 */
3266 	static
3267 	SCIP_DECL_SORTPTRCOMP(enfodataCmp)
3268 	{
3269 	   SCIP_NLHDLR* h1;
3270 	   SCIP_NLHDLR* h2;
3271 	
3272 	   assert(elem1 != NULL);
3273 	   assert(elem2 != NULL);
3274 	
3275 	   h1 = ((EXPRENFO*)elem1)->nlhdlr;
3276 	   h2 = ((EXPRENFO*)elem2)->nlhdlr;
3277 	
3278 	   assert(h1 != NULL);
3279 	   assert(h2 != NULL);
3280 	
3281 	   if( SCIPnlhdlrGetEnfoPriority(h1) != SCIPnlhdlrGetEnfoPriority(h2) )
3282 	      return SCIPnlhdlrGetEnfoPriority(h1) - SCIPnlhdlrGetEnfoPriority(h2);
3283 	
3284 	   if( SCIPnlhdlrGetDetectPriority(h1) != SCIPnlhdlrGetDetectPriority(h2) )
3285 	      return SCIPnlhdlrGetDetectPriority(h1) - SCIPnlhdlrGetDetectPriority(h2);
3286 	
3287 	   return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3288 	}
3289 	
3290 	/** install nlhdlrs in one expression */
3291 	static
3292 	SCIP_RETCODE detectNlhdlr(
3293 	   SCIP*                 scip,               /**< SCIP data structure */
3294 	   SCIP_EXPR*            expr,               /**< expression for which to run detection routines */
3295 	   SCIP_CONS*            cons                /**< constraint for which expr == consdata->expr, otherwise NULL */
3296 	   )
3297 	{
3298 	   SCIP_EXPR_OWNERDATA* ownerdata;
3299 	   SCIP_CONSHDLRDATA* conshdlrdata;
3300 	   SCIP_NLHDLR_METHOD enforcemethodsallowed;
3301 	   SCIP_NLHDLR_METHOD enforcemethods;
3302 	   SCIP_NLHDLR_METHOD enforcemethodsnew;
3303 	   SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3304 	   SCIP_NLHDLR_METHOD nlhdlrparticipating;
3305 	   SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3306 	   int enfossize;  /* allocated length of expr->enfos array */
3307 	   int h;
3308 	
3309 	   assert(expr != NULL);
3310 	
3311 	   ownerdata = SCIPexprGetOwnerData(expr);
3312 	   assert(ownerdata != NULL);
3313 	
3314 	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3315 	   assert(conshdlrdata != NULL);
3316 	   assert(conshdlrdata->auxvarid >= 0);
3317 	   assert(!conshdlrdata->indetect);
3318 	
3319 	   /* there should be no enforcer yet and detection should not even have considered expr yet */
3320 	   assert(ownerdata->nenfos < 0);
3321 	   assert(ownerdata->enfos == NULL);
3322 	
3323 	   /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3324 	    * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3325 	    * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3326 	    * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3327 	    * - if no one uses activity, then do not need activity methods
3328 	    */
3329 	   enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3330 	   if( ownerdata->nauxvaruses == 0 )
3331 	      enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3332 	   else
3333 	   {
3334 	      if( ownerdata->nlockspos == 0 )  /* no need for underestimation */
3335 	         enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3336 	      if( ownerdata->nlocksneg == 0 )  /* no need for overestimation */
3337 	         enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3338 	   }
3339 	   if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3340 	      enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3341 	
3342 	   /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3343 	   assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3344 	
3345 	   /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3346 	   enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3347 	
3348 	   ownerdata->nenfos = 0;
3349 	   enfossize = 2;
3350 	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3351 	   conshdlrdata->indetect = TRUE;
3352 	
3353 	   SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3354 	      cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3355 	      (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3356 	      (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3357 	      (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3358 	
3359 	   for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3360 	   {
3361 	      SCIP_NLHDLR* nlhdlr;
3362 	
3363 	      nlhdlr = conshdlrdata->nlhdlrs[h];
3364 	      assert(nlhdlr != NULL);
3365 	
3366 	      /* skip disabled nlhdlrs */
3367 	      if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3368 	         continue;
3369 	
3370 	      /* call detect routine of nlhdlr */
3371 	      nlhdlrexprdata = NULL;
3372 	      enforcemethodsnew = enforcemethods;
3373 	      nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3374 	      conshdlrdata->registerusesactivitysepabelow = FALSE;  /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3375 	      conshdlrdata->registerusesactivitysepaabove = FALSE;  /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3376 	      /* coverity[forward_null] */
3377 	      SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3378 	
3379 	      /* nlhdlr might have claimed more than needed: clean up sepa flags */
3380 	      nlhdlrparticipating &= enforcemethodsallowed;
3381 	
3382 	      /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3383 	      assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3384 	
3385 	      /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3386 	       * They are also cleaned up here to ensure that only the needed methods are claimed.
3387 	       */
3388 	      nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3389 	
3390 	      /* nlhdlr needs to participate for the methods it is enforcing */
3391 	      assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3392 	
3393 	      if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3394 	      {
3395 	         /* nlhdlr might not have detected anything, or all set flags might have been removed by
3396 	          * clean up; in the latter case, we may need to free nlhdlrexprdata */
3397 	
3398 	         /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3399 	         if( nlhdlrexprdata != NULL )
3400 	         {
3401 	            SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3402 	         }
3403 	         /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3404 	         assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3405 	
3406 	         SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3407 	
3408 	         continue;
3409 	      }
3410 	
3411 	      SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3412 	         SCIPnlhdlrGetName(nlhdlr),
3413 	         ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3414 	         ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3415 	         ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3416 	
3417 	      /* store nlhdlr and its data */
3418 	      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3419 	      SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3420 	      ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3421 	      ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3422 	      ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3423 	      ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3424 	      ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3425 	      ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3426 	      ownerdata->nenfos++;
3427 	
3428 	      /* update enforcement flags */
3429 	      enforcemethods = enforcemethodsnew;
3430 	   }
3431 	
3432 	   conshdlrdata->indetect = FALSE;
3433 	
3434 	   /* stop if an enforcement method is missing but we are already in solving stage
3435 	    * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3436 	    */
3437 	   if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3438 	   {
3439 	      SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3440 	      return SCIP_ERROR;
3441 	   }
3442 	
3443 	   assert(ownerdata->nenfos > 0);
3444 	
3445 	   /* sort nonlinear handlers by enforcement priority, in decreasing order */
3446 	   if( ownerdata->nenfos > 1 )
3447 	      SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3448 	
3449 	   /* resize enfos array to be nenfos long */
3450 	   SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3451 	
3452 	   return SCIP_OKAY;
3453 	}
3454 	
3455 	/** detect nlhdlrs that can handle the expressions */
3456 	static
3457 	SCIP_RETCODE detectNlhdlrs(
3458 	   SCIP*                 scip,               /**< SCIP data structure */
3459 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3460 	   SCIP_CONS**           conss,              /**< constraints for which to run nlhdlr detect */
3461 	   int                   nconss              /**< total number of constraints */
3462 	   )
3463 	{
3464 	   SCIP_CONSHDLRDATA* conshdlrdata;
3465 	   SCIP_CONSDATA* consdata;
3466 	   SCIP_EXPR* expr;
3467 	   SCIP_EXPR_OWNERDATA* ownerdata;
3468 	   SCIP_EXPRITER* it;
3469 	   int i;
3470 	
3471 	   assert(conss != NULL || nconss == 0);
3472 	   assert(nconss >= 0);
3473 	   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 */
3474 	
3475 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
3476 	   assert(conshdlrdata != NULL);
3477 	
3478 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3479 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, TRUE) );
3480 	
3481 	   if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3482 	   {
3483 	      /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3484 	       * for example, this happens if globally valid nonlinear constraints are added during the tree search
3485 	       */
3486 	      SCIPincrementCurBoundsTagNonlinear(conshdlr, TRUE);
3487 	      conshdlrdata->globalbounds = TRUE;
3488 	      conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3489 	   }
3490 	
3491 	   for( i = 0; i < nconss; ++i )
3492 	   {
3493 	      assert(conss != NULL && conss[i] != NULL);
3494 	
3495 	      consdata = SCIPconsGetData(conss[i]);
3496 	      assert(consdata != NULL);
3497 	      assert(consdata->expr != NULL);
3498 	
3499 	      /* if a constraint is separated, we currently need it to be initial, too
3500 	       * this is because INITLP will create the auxiliary variables that are used for any separation
3501 	       * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3502 	       */
3503 	      assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3504 	
3505 	      ownerdata = SCIPexprGetOwnerData(consdata->expr);
3506 	      assert(ownerdata != NULL);
3507 	
3508 	      /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3509 	       * then we would normally skip to run DETECT again
3510 	       * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3511 	       * thus, if expr is the root expression, we rerun DETECT
3512 	       */
3513 	      if( ownerdata->nenfos > 0 )
3514 	      {
3515 	         SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3516 	         assert(ownerdata->nenfos < 0);
3517 	      }
3518 	
3519 	      /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3520 	       *   this way we can treat the root expression like any other expression when enforcing via separation
3521 	       * if constraint will be propagated, then register activity usage of root expression
3522 	       * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3523 	       */
3524 	      conshdlrdata->indetect = TRUE;
3525 	      SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, consdata->expr,
3526 	         SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3527 	         SCIPconsIsPropagated(conss[i]),
3528 	         FALSE, FALSE) );
3529 	      conshdlrdata->indetect = FALSE;
3530 	
3531 	      /* compute integrality information for all subexpressions */
3532 	      SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3533 	
3534 	      /* run detectNlhdlr on all expr where required */
3535 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3536 	      {
3537 	         ownerdata = SCIPexprGetOwnerData(expr);
3538 	         assert(ownerdata != NULL);
3539 	
3540 	         /* skip exprs that we already looked at */
3541 	         if( ownerdata->nenfos >= 0 )
3542 	            continue;
3543 	
3544 	         /* if there is use of the auxvar, then someone requires that
3545 	          *   auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3546 	          *   thus, we need to find nlhdlrs that separate or estimate
3547 	          * if there is use of the activity, then there is someone requiring that
3548 	          *   activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3549 	          *   thus, we need to find nlhdlrs that do interval-evaluation
3550 	          */
3551 	         if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3552 	         {
3553 	            SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3554 	
3555 	            assert(ownerdata->nenfos >= 0);
3556 	         }
3557 	         else
3558 	         {
3559 	            /* remember that we looked at this expression during detectNlhdlrs
3560 	             * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3561 	             * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3562 	             * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3563 	             */
3564 	            ownerdata->nenfos = 0;
3565 	         }
3566 	      }
3567 	
3568 	      /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3569 	      if( SCIPconsIsPropagated(conss[i]) )
3570 	         consdata->ispropagated = FALSE;
3571 	   }
3572 	
3573 	   if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3574 	   {
3575 	      /* ensure that the local bounds are used again when reevaluating the expressions later;
3576 	       * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3577 	       */
3578 	      SCIPincrementCurBoundsTagNonlinear(conshdlr, FALSE);
3579 	      conshdlrdata->globalbounds = FALSE;
3580 	      conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3581 	   }
3582 	   else
3583 	   {
3584 	      /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3585 	      SCIPincrementCurBoundsTagNonlinear(conshdlr, FALSE);
3586 	   }
3587 	
3588 	   SCIPfreeExpriter(&it);
3589 	
3590 	   return SCIP_OKAY;
3591 	}
3592 	
3593 	/** initializes (pre)solving data of constraints
3594 	 *
3595 	 * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3596 	 * not be modified.
3597 	 * In particular, this function
3598 	 * - runs the detection method of nlhldrs
3599 	 * - looks for unlocked linear variables
3600 	 * - checks curvature (if not in presolve)
3601 	 * - creates and add row to NLP (if not in presolve)
3602 	 *
3603 	 * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3604 	 * e.g., it should be called in INITSOL and for constraints that are added during solve.
3605 	 */
3606 	static
3607 	SCIP_RETCODE initSolve(
3608 	   SCIP*                 scip,               /**< SCIP data structure */
3609 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3610 	   SCIP_CONS**           conss,              /**< constraints */
3611 	   int                   nconss              /**< number of constraints */
3612 	   )
3613 	{
3614 	   int c;
3615 	
3616 	   for( c = 0; c < nconss; ++c )
3617 	   {
3618 	      /* check for a linear variable that can be increase or decreased without harming feasibility */
3619 	      findUnlockedLinearVar(scip, conss[c]);
3620 	
3621 	      if( SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3622 	      {
3623 	         SCIP_CONSDATA* consdata;
3624 	         SCIP_Bool success = FALSE;
3625 	
3626 	         consdata = SCIPconsGetData(conss[c]);  /*lint !e613*/
3627 	         assert(consdata != NULL);
3628 	         assert(consdata->expr != NULL);
3629 	
3630 	         if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3631 	         {
3632 	            /* call the curvature detection algorithm of the convex nonlinear handler
3633 	             * Check only for those curvature that may result in a convex inequality, i.e.,
3634 	             * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3635 	             * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3636 	             */
3637 	            if( !SCIPisInfinity(scip, -consdata->lhs) )
3638 	            {
3639 	               SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3640 	               if( success )
3641 	                  consdata->curv = SCIP_EXPRCURV_CONCAVE;
3642 	            }
3643 	            if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3644 	            {
3645 	               SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3646 	               if( success )
3647 	                  consdata->curv = SCIP_EXPRCURV_CONVEX;
3648 	            }
3649 	         }
3650 	         else
3651 	         {
3652 	            if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3653 	            {
3654 	               SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3655 	               consdata->curv = SCIP_EXPRCURV_LINEAR;
3656 	            }
3657 	            else
3658 	            {
3659 	               consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3660 	            }
3661 	         }
3662 	         SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3663 	
3664 	         /* add nlrow representation to NLP, if NLP had been constructed */
3665 	         if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3666 	         {
3667 	            if( consdata->nlrow == NULL )
3668 	            {
3669 	               SCIP_CALL( createNlRow(scip, conss[c]) );
3670 	               assert(consdata->nlrow != NULL);
3671 	            }
3672 	            SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
3673 	            SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3674 	         }
3675 	      }
3676 	   }
3677 	
3678 	   /* register non linear handlers */
3679 	   SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3680 	
3681 	   return SCIP_OKAY;
3682 	}
3683 	
3684 	/** deinitializes (pre)solving data of constraints
3685 	 *
3686 	 * This removes the initialization data created in initSolve().
3687 	 *
3688 	 * This function can be called in presolve and solve.
3689 	 *
3690 	 * TODO At the moment, it should not be called for a constraint if there are other constraints
3691 	 * that use the same expressions but still require their nlhdlr.
3692 	 * We should probably only decrement the auxvar and activity usage for the root expr and then
3693 	 * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3694 	 */
3695 	static
3696 	SCIP_RETCODE deinitSolve(
3697 	   SCIP*                 scip,               /**< SCIP data structure */
3698 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3699 	   SCIP_CONS**           conss,              /**< constraints */
3700 	   int                   nconss              /**< number of constraints */
3701 	   )
3702 	{
3703 	   SCIP_EXPRITER* it;
3704 	   SCIP_EXPR* expr;
3705 	   SCIP_CONSDATA* consdata;
3706 	   SCIP_Bool rootactivityvalid;
3707 	   int c;
3708 	
3709 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3710 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
3711 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_LEAVEEXPR);
3712 	
3713 	   /* call deinitialization callbacks of expression and nonlinear handlers
3714 	    * free nonlinear handlers information from expressions
3715 	    * remove auxiliary variables and nactivityuses counts from expressions
3716 	    */
3717 	   for( c = 0; c < nconss; ++c )
3718 	   {
3719 	      assert(conss != NULL);
3720 	      assert(conss[c] != NULL);
3721 	
3722 	      consdata = SCIPconsGetData(conss[c]);
3723 	      assert(consdata != NULL);
3724 	      assert(consdata->expr != NULL);
3725 	
3726 	      /* check and remember whether activity in root is valid */
3727 	      rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3728 	
3729 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3730 	      {
3731 	         SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3732 	
3733 	         /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3734 	         SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3735 	
3736 	         /* remove quadratic info */
3737 	         SCIPfreeExprQuadratic(scip, expr);
3738 	
3739 	         if( rootactivityvalid )
3740 	         {
3741 	            /* ensure activity is valid if consdata->expr activity is valid
3742 	             * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3743 	             * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3744 	             * so this childs activity would be invalid, which can generate confusion
3745 	             */
3746 	            SCIP_CALL( SCIPevalExprActivity(scip, expr) );
3747 	         }
3748 	      }
3749 	
3750 	      if( consdata->nlrow != NULL )
3751 	      {
3752 	         /* remove row from NLP, if still in solving
3753 	          * if we are in exitsolve, the whole NLP will be freed anyway
3754 	          */
3755 	         if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3756 	         {
3757 	            SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3758 	         }
3759 	
3760 	         SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3761 	      }
3762 	
3763 	      /* forget about linear variables that can be increased or decreased without harming feasibility */
3764 	      consdata->linvardecr = NULL;
3765 	      consdata->linvarincr = NULL;
3766 	
3767 	      /* forget about curvature */
3768 	      consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3769 	   }
3770 	
3771 	   SCIPfreeExpriter(&it);
3772 	
3773 	   return SCIP_OKAY;
3774 	}
3775 	
3776 	/** helper method to decide whether a given expression is product of at least two binary variables */
3777 	static
3778 	SCIP_Bool isBinaryProduct(
3779 	   SCIP*                 scip,               /**< SCIP data structure */
3780 	   SCIP_EXPR*            expr                /**< expression */
3781 	   )
3782 	{
3783 	   int i;
3784 	
3785 	   assert(expr != NULL);
3786 	
3787 	   /* check whether the expression is a product */
3788 	   if( !SCIPisExprProduct(scip, expr) )
3789 	      return FALSE;
3790 	
3791 	   /* don't consider products with a coefficient != 1 and products with a single child
3792 	    * simplification will take care of this expression later
3793 	    */
3794 	   if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3795 	      return FALSE;
3796 	
3797 	   for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3798 	   {
3799 	      SCIP_EXPR* child;
3800 	      SCIP_VAR* var;
3801 	      SCIP_Real ub;
3802 	      SCIP_Real lb;
3803 	
3804 	      child = SCIPexprGetChildren(expr)[i];
3805 	      assert(child != NULL);
3806 	
3807 	      if( !SCIPisExprVar(scip, child) )
3808 	         return FALSE;
3809 	
3810 	      var = SCIPgetVarExprVar(child);
3811 	      lb = SCIPvarGetLbLocal(var);
3812 	      ub = SCIPvarGetUbLocal(var);
3813 	
3814 	      /* check whether variable is integer and has [0,1] as variable bounds */
3815 	      if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3816 	         return FALSE;
3817 	   }
3818 	
3819 	   return TRUE;
3820 	}
3821 	
3822 	/** helper method to collect all bilinear binary product terms */
3823 	static
3824 	SCIP_RETCODE getBilinearBinaryTerms(
3825 	   SCIP*                 scip,               /**< SCIP data structure */
3826 	   SCIP_EXPR*            sumexpr,            /**< sum expression */
3827 	   SCIP_VAR**            xs,                 /**< array to collect first variable of each bilinear binary product */
3828 	   SCIP_VAR**            ys,                 /**< array to collect second variable of each bilinear binary product */
3829 	   int*                  childidxs,          /**< array to store the index of the child of each stored bilinear binary product */
3830 	   int*                  nterms              /**< pointer to store the total number of bilinear binary terms */
3831 	   )
3832 	{
3833 	   int i;
3834 	
3835 	   assert(sumexpr != NULL);
3836 	   assert(SCIPisExprSum(scip, sumexpr));
3837 	   assert(xs != NULL);
3838 	   assert(ys != NULL);
3839 	   assert(childidxs != NULL);
3840 	   assert(nterms != NULL);
3841 	
3842 	   *nterms = 0;
3843 	
3844 	   for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3845 	   {
3846 	      SCIP_EXPR* child;
3847 	
3848 	      child = SCIPexprGetChildren(sumexpr)[i];
3849 	      assert(child != NULL);
3850 	
3851 	      if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3852 	      {
3853 	         SCIP_VAR* x = SCIPgetVarExprVar(SCIPexprGetChildren(child)[0]);
3854 	         SCIP_VAR* y = SCIPgetVarExprVar(SCIPexprGetChildren(child)[1]);
3855 	
3856 	         assert(x != NULL);
3857 	         assert(y != NULL);
3858 	
3859 	         if( x != y )
3860 	         {
3861 	            xs[*nterms] = x;
3862 	            ys[*nterms] = y;
3863 	            childidxs[*nterms] = i;
3864 	            ++(*nterms);
3865 	         }
3866 	      }
3867 	   }
3868 	
3869 	   return SCIP_OKAY;
3870 	}
3871 	
3872 	/** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3873 	static
3874 	SCIP_RETCODE reformulateFactorizedBinaryQuadratic(
3875 	   SCIP*                 scip,               /**< SCIP data structure */
3876 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3877 	   SCIP_CONS*            cons,               /**< constraint */
3878 	   SCIP_VAR*             facvar,             /**< variable that has been factorized */
3879 	   SCIP_VAR**            vars,               /**< variables of sum_j c_ij x_j */
3880 	   SCIP_Real*            coefs,              /**< coefficients of sum_j c_ij x_j */
3881 	   int                   nvars,              /**< total number of variables in sum_j c_ij x_j */
3882 	   SCIP_EXPR**           newexpr,            /**< pointer to store the new expression */
3883 	   int*                  naddconss           /**< pointer to update the total number of added constraints (might be NULL) */
3884 	   )
3885 	{
3886 	   SCIP_VAR* auxvar;
3887 	   SCIP_CONS* newcons;
3888 	   SCIP_Real minact = 0.0;
3889 	   SCIP_Real maxact = 0.0;
3890 	   SCIP_Bool integral = TRUE;
3891 	   char name [SCIP_MAXSTRLEN];
3892 	   int i;
3893 	
3894 	   assert(facvar != NULL);
3895 	   assert(vars != NULL);
3896 	   assert(nvars > 1);
3897 	   assert(newexpr != NULL);
3898 	
3899 	   /* compute minimum and maximum activity of sum_j c_ij x_j */
3900 	   /* 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 */
3901 	   for( i = 0; i < nvars; ++i )
3902 	   {
3903 	      minact += MIN(coefs[i], 0.0);
3904 	      maxact += MAX(coefs[i], 0.0);
3905 	      integral = integral && SCIPisIntegral(scip, coefs[i]);
3906 	   }
3907 	   assert(minact <= maxact);
3908 	
3909 	   /* create and add auxiliary variable */
3910 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3911 	   SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
3912 	   SCIP_CALL( SCIPaddVar(scip, auxvar) );
3913 	
3914 	   /* create and add z - maxact x <= 0 */
3915 	   if( !SCIPisZero(scip, maxact) )
3916 	   {
3917 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3918 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3919 	      SCIP_CALL( SCIPaddCons(scip, newcons) );
3920 	      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3921 	      if( naddconss != NULL )
3922 	         ++(*naddconss);
3923 	   }
3924 	
3925 	   /* create and add  0 <= z - minact x */
3926 	   if( !SCIPisZero(scip, minact) )
3927 	   {
3928 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3929 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
3930 	      SCIP_CALL( SCIPaddCons(scip, newcons) );
3931 	      SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3932 	      if( naddconss != NULL )
3933 	         ++(*naddconss);
3934 	   }
3935 	
3936 	   /* create and add minact <= sum_j c_j x_j - z + minact x_i */
3937 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3938 	   SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
3939 	   SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3940 	   if( !SCIPisZero(scip, minact) )
3941 	   {
3942 	      SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
3943 	   }
3944 	   SCIP_CALL( SCIPaddCons(scip, newcons) );
3945 	   SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3946 	   if( naddconss != NULL )
3947 	      ++(*naddconss);
3948 	
3949 	   /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
3950 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3951 	   SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
3952 	   SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3953 	   if( !SCIPisZero(scip, maxact) )
3954 	   {
3955 	      SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
3956 	   }
3957 	   SCIP_CALL( SCIPaddCons(scip, newcons) );
3958 	   SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3959 	   if( naddconss != NULL )
3960 	      ++(*naddconss);
3961 	
3962 	   /* create variable expression */
3963 	   SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
3964 	
3965 	   /* release auxvar */
3966 	   SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3967 	
3968 	   return SCIP_OKAY;
3969 	}
3970 	
3971 	/** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
3972 	static
3973 	SCIP_RETCODE getFactorizedBinaryQuadraticExpr(
3974 	   SCIP*                 scip,               /**< SCIP data structure */
3975 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
3976 	   SCIP_CONS*            cons,               /**< constraint */
3977 	   SCIP_EXPR*            sumexpr,            /**< expression */
3978 	   int                   minterms,           /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
3979 	   SCIP_EXPR**           newexpr,            /**< pointer to store the expression that represents the binary quadratic */
3980 	   int*                  naddconss           /**< pointer to update the total number of added constraints (might be NULL) */
3981 	   )
3982 	{
3983 	   SCIP_EXPR** exprs = NULL;
3984 	   SCIP_VAR** tmpvars = NULL;
3985 	   SCIP_VAR** vars = NULL;
3986 	   SCIP_VAR** xs = NULL;
3987 	   SCIP_VAR** ys = NULL;
3988 	   SCIP_Real* exprcoefs = NULL;
3989 	   SCIP_Real* tmpcoefs = NULL;
3990 	   SCIP_Real* sumcoefs;
3991 	   SCIP_Bool* isused  = NULL;
3992 	   int* childidxs = NULL;
3993 	   int* count = NULL;
3994 	   int nchildren;
3995 	   int nexprs = 0;
3996 	   int nterms;
3997 	   int nvars;
3998 	   int ntotalvars;
3999 	   int i;
4000 	
4001 	   assert(sumexpr != NULL);
4002 	   assert(minterms > 1);
4003 	   assert(newexpr != NULL);
4004 	
4005 	   *newexpr = NULL;
4006 	
4007 	   /* check whether sumexpr is indeed a sum */
4008 	   if( !SCIPisExprSum(scip, sumexpr) )
4009 	      return SCIP_OKAY;
4010 	
4011 	   nchildren = SCIPexprGetNChildren(sumexpr);
4012 	   sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4013 	   nvars = SCIPgetNVars(scip);
4014 	   ntotalvars = SCIPgetNTotalVars(scip);
4015 	
4016 	   /* check whether there are enough terms available */
4017 	   if( nchildren < minterms )
4018 	      return SCIP_OKAY;
4019 	
4020 	   /* allocate memory */
4021 	   SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4022 	   SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4023 	   SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4024 	
4025 	   /* collect all bilinear binary product terms */
4026 	   SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4027 	
4028 	   /* check whether there are enough terms available */
4029 	   if( nterms < minterms )
4030 	      goto TERMINATE;
4031 	
4032 	   /* store how often each variable appears in a bilinear binary product */
4033 	   SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
4034 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4035 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4036 	
4037 	   SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4038 	   SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4039 	   SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4040 	   SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4041 	
4042 	   for( i = 0; i < nterms; ++i )
4043 	   {
4044 	      int xidx;
4045 	      int yidx;
4046 	
4047 	      assert(xs[i] != NULL);
4048 	      assert(ys[i] != NULL);
4049 	
4050 	      xidx = SCIPvarGetIndex(xs[i]);
4051 	      assert(xidx < ntotalvars);
4052 	      yidx = SCIPvarGetIndex(ys[i]);
4053 	      assert(yidx < ntotalvars);
4054 	
4055 	      ++count[xidx];
4056 	      ++count[yidx];
4057 	
4058 	      SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4059 	      SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4060 	   }
4061 	
4062 	   /* sort variables; don't change order of count array because it depends on problem indices */
4063 	   {
4064 	      int* tmpcount;
4065 	
4066 	      SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4067 	      SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4068 	      SCIPfreeBufferArray(scip, &tmpcount);
4069 	   }
4070 	
4071 	   for( i = 0; i < nvars; ++i )
4072 	   {
4073 	      SCIP_VAR* facvar = vars[i];
4074 	      int ntmpvars = 0;
4075 	      int j;
4076 	
4077 	      /* skip candidate if there are not enough terms left */
4078 	      if( count[SCIPvarGetIndex(vars[i])] < minterms )
4079 	         continue;
4080 	
4081 	      SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4082 	
4083 	      /* collect variables for x_i * sum_j c_ij x_j */
4084 	      for( j = 0; j < nterms; ++j )
4085 	      {
4086 	         int childidx = childidxs[j];
4087 	         assert(childidx >= 0 && childidx < nchildren);
4088 	
4089 	         if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4090 	         {
4091 	            SCIP_Real coef;
4092 	            int xidx;
4093 	            int yidx;
4094 	
4095 	            coef = sumcoefs[childidx];
4096 	            assert(coef != 0.0);
4097 	
4098 	            /* collect corresponding variable */
4099 	            tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4100 	            tmpcoefs[ntmpvars] = coef;
4101 	            ++ntmpvars;
4102 	
4103 	            /* update counters */
4104 	            xidx = SCIPvarGetIndex(xs[j]);
4105 	            assert(xidx < ntotalvars);
4106 	            yidx = SCIPvarGetIndex(ys[j]);
4107 	            assert(yidx < ntotalvars);
4108 	            --count[xidx];
4109 	            --count[yidx];
4110 	            assert(count[xidx] >= 0);
4111 	            assert(count[yidx] >= 0);
4112 	
4113 	            /* mark term to be used */
4114 	            isused[childidx] = TRUE;
4115 	         }
4116 	      }
4117 	      assert(ntmpvars >= minterms);
4118 	      assert(SCIPvarGetIndex(facvar) < ntotalvars);
4119 	      assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4120 	
4121 	      /* create required constraints and store the generated expression */
4122 	      SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4123 	      exprcoefs[nexprs] = 1.0;
4124 	      ++nexprs;
4125 	   }
4126 	
4127 	   /* factorization was only successful if at least one expression has been generated */
4128 	   if( nexprs > 0 )
4129 	   {
4130 	      int nexprsold = nexprs;
4131 	
4132 	      /* add all children of the sum that have not been used */
4133 	      for( i = 0; i < nchildren; ++i )
4134 	      {
4135 	         if( !isused[i] )
4136 	         {
4137 	            exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4138 	            exprcoefs[nexprs] = sumcoefs[i];
4139 	            ++nexprs;
4140 	         }
4141 	      }
4142 	
4143 	      /* create a new sum expression */
4144 	      SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4145 	
4146 	      /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4147 	      for( i = 0; i < nexprsold; ++i )
4148 	      {
4149 	         SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4150 	      }
4151 	   }
4152 	
4153 	TERMINATE:
4154 	   /* free memory */
4155 	   SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4156 	   SCIPfreeBufferArrayNull(scip, &tmpvars);
4157 	   SCIPfreeBufferArrayNull(scip, &exprcoefs);
4158 	   SCIPfreeBufferArrayNull(scip, &exprs);
4159 	   SCIPfreeBufferArrayNull(scip, &vars);
4160 	   SCIPfreeBufferArrayNull(scip, &isused);
4161 	   SCIPfreeBufferArrayNull(scip, &count);
4162 	   SCIPfreeBufferArray(scip, &childidxs);
4163 	   SCIPfreeBufferArray(scip, &ys);
4164 	   SCIPfreeBufferArray(scip, &xs);
4165 	
4166 	   return SCIP_OKAY;
4167 	}
4168 	
4169 	/** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4170 	static
4171 	SCIP_RETCODE getBinaryProductExprDo(
4172 	   SCIP*                 scip,               /**< SCIP data structure */
4173 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4174 	   SCIP_EXPR*            prodexpr,           /**< product expression */
4175 	   SCIP_EXPR**           newexpr,            /**< pointer to store the expression that represents the product */
4176 	   int*                  naddconss,          /**< pointer to update the total number of added constraints (might be NULL) */
4177 	   SCIP_Bool             empathy4and         /**< whether to use an AND constraint, if possible */
4178 	   )
4179 	{
4180 	   SCIP_VAR** vars;
4181 	   SCIP_CONS* cons;
4182 	   SCIP_Real* coefs;
4183 	   SCIP_VAR* w;
4184 	   char* name;
4185 	   int nchildren;
4186 	   int i;
4187 	
4188 	   assert(conshdlr != NULL);
4189 	   assert(prodexpr != NULL);
4190 	   assert(SCIPisExprProduct(scip, prodexpr));
4191 	   assert(newexpr != NULL);
4192 	
4193 	   nchildren = SCIPexprGetNChildren(prodexpr);
4194 	   assert(nchildren >= 2);
4195 	
4196 	   /* memory to store the variables of the variable expressions (+1 for w) and their name */
4197 	   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4198 	   SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4199 	   SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4200 	
4201 	   /* prepare the names of the variable and the constraints */
4202 	   strcpy(name, "binreform");
4203 	   for( i = 0; i < nchildren; ++i )
4204 	   {
4205 	      vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4206 	      coefs[i] = 1.0;
4207 	      assert(vars[i] != NULL);
4208 	      (void) strcat(name, "_");
4209 	      (void) strcat(name, SCIPvarGetName(vars[i]));
4210 	   }
4211 	
4212 	   /* create and add variable */
4213 	   SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4214 	   SCIP_CALL( SCIPaddVar(scip, w) );
4215 	   SCIPdebugMsg(scip, "  created auxiliary variable %s\n", name);
4216 	
4217 	   /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4218 	   if( nchildren == 2 && !empathy4and )
4219 	   {
4220 	      SCIP_VAR* x = vars[0];
4221 	      SCIP_VAR* y = vars[1];
4222 	
4223 	      assert(x != NULL);
4224 	      assert(y != NULL);
4225 	      assert(x != y);
4226 	
4227 	      /* create and add x - w >= 0 */
4228 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4229 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4230 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4231 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4232 	
4233 	      /* create and add y - w >= 0 */
4234 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4235 	      SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4236 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4237 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4238 	
4239 	      /* create and add x + y - w <= 1 */
4240 	      vars[2] = w;
4241 	      coefs[2] = -1.0;
4242 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4243 	      SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4244 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4245 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4246 	
4247 	      /* update number of added constraints */
4248 	      if( naddconss != NULL )
4249 	         *naddconss += 3;
4250 	   }
4251 	   else
4252 	   {
4253 	      /* create, add, and release AND constraint */
4254 	      SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4255 	      SCIP_CALL( SCIPaddCons(scip, cons) );
4256 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4257 	      SCIPdebugMsg(scip, "  create AND constraint\n");
4258 	
4259 	      /* update number of added constraints */
4260 	      if( naddconss != NULL )
4261 	         *naddconss += 1;
4262 	   }
4263 	
4264 	   /* create variable expression */
4265 	   SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4266 	
4267 	   /* release created variable */
4268 	   SCIP_CALL( SCIPreleaseVar(scip, &w) );
4269 	
4270 	   /* free memory */
4271 	   SCIPfreeBufferArray(scip, &name);
4272 	   SCIPfreeBufferArray(scip, &coefs);
4273 	   SCIPfreeBufferArray(scip, &vars);
4274 	
4275 	   return SCIP_OKAY;
4276 	}
4277 	
4278 	/** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4279 	static
4280 	SCIP_RETCODE getBinaryProductExpr(
4281 	   SCIP*                 scip,               /**< SCIP data structure */
4282 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4283 	   SCIP_HASHMAP*         exprmap,            /**< map to remember generated variables for visited product expressions */
4284 	   SCIP_EXPR*            prodexpr,           /**< product expression */
4285 	   SCIP_EXPR**           newexpr,            /**< pointer to store the expression that represents the product */
4286 	   int*                  naddconss,          /**< pointer to update the total number of added constraints (might be NULL) */
4287 	   int*                  nchgcoefs           /**< pointer to update the total number of changed coefficients (might be NULL) */
4288 	   )
4289 	{
4290 	   SCIP_CONSHDLRDATA* conshdlrdata;
4291 	   int nchildren;
4292 	
4293 	   assert(prodexpr != NULL);
4294 	   assert(newexpr != NULL);
4295 	
4296 	   *newexpr = NULL;
4297 	
4298 	   /* only consider products of binary variables */
4299 	   if( !isBinaryProduct(scip, prodexpr) )
4300 	      return SCIP_OKAY;
4301 	
4302 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4303 	   assert(conshdlrdata != NULL);
4304 	   nchildren = SCIPexprGetNChildren(prodexpr);
4305 	   assert(nchildren >= 2);
4306 	
4307 	   /* check whether there is already an expression that represents the product */
4308 	   if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4309 	   {
4310 	      *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4311 	      assert(*newexpr != NULL);
4312 	
4313 	      /* capture expression */
4314 	      SCIPcaptureExpr(*newexpr);
4315 	   }
4316 	   else
4317 	   {
4318 	      SCIPdebugMsg(scip, "  product expression %p has been considered for the first time\n", (void*)prodexpr);
4319 	
4320 	      if( nchildren == 2 )
4321 	      {
4322 	         SCIP_CLIQUE** xcliques;
4323 	         SCIP_VAR* x;
4324 	         SCIP_VAR* y;
4325 	         SCIP_Bool found_clique = FALSE;
4326 	         int c;
4327 	
4328 	         /* get variables from the product expression */
4329 	         x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4330 	         assert(x != NULL);
4331 	         y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4332 	         assert(y != NULL);
4333 	         assert(x != y);
4334 	
4335 	         /* first try to find a clique containing both variables */
4336 	         xcliques = SCIPvarGetCliques(x, TRUE);
4337 	
4338 	         /* look in cliques containing x */
4339 	         for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4340 	         {
4341 	            if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4342 	            {
4343 	               /* create zero value expression */
4344 	               SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4345 	
4346 	               if( nchgcoefs != NULL )
4347 	                  *nchgcoefs += 1;
4348 	
4349 	               found_clique = TRUE;
4350 	               break;
4351 	            }
4352 	
4353 	            if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4354 	            {
4355 	               /* create variable expression for x */
4356 	               SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4357 	
4358 	               if( nchgcoefs != NULL )
4359 	                  *nchgcoefs += 2;
4360 	
4361 	               found_clique = TRUE;
4362 	               break;
4363 	            }
4364 	         }
4365 	
4366 	         if( !found_clique )
4367 	         {
4368 	            xcliques = SCIPvarGetCliques(x, FALSE);
4369 	
4370 	            /* look in cliques containing complement of x */
4371 	            for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4372 	            {
4373 	               if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4374 	               {
4375 	                  /* create variable expression for y */
4376 	                  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4377 	
4378 	                  if( nchgcoefs != NULL )
4379 	                     *nchgcoefs += 1;
4380 	
4381 	                  found_clique = TRUE;
4382 	                  break;
4383 	               }
4384 	
4385 	               if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4386 	               {
4387 	                  /* create sum expression */
4388 	                  SCIP_EXPR* sum_children[2];
4389 	                  SCIP_Real sum_coefs[2];
4390 	                  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4391 	                  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4392 	                  sum_coefs[0] = 1.0;
4393 	                  sum_coefs[1] = 1.0;
4394 	                  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4395 	
4396 	                  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4397 	                  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4398 	
4399 	                  if( nchgcoefs != NULL )
4400 	                     *nchgcoefs += 3;
4401 	
4402 	                  found_clique = TRUE;
4403 	                  break;
4404 	               }
4405 	            }
4406 	         }
4407 	
4408 	         /* if the variables are not in a clique, do standard linearization */
4409 	         if( !found_clique )
4410 	         {
4411 	            SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4412 	         }
4413 	      }
4414 	      else
4415 	      {
4416 	         /* linearize binary product using an AND constraint because nchildren > 2 */
4417 	         SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4418 	      }
4419 	
4420 	      /* hash variable expression */
4421 	      SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4422 	   }
4423 	
4424 	   return SCIP_OKAY;
4425 	}
4426 	
4427 	/** helper function to replace binary products in a given constraint */
4428 	static
4429 	SCIP_RETCODE replaceBinaryProducts(
4430 	   SCIP*                 scip,               /**< SCIP data structure */
4431 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4432 	   SCIP_CONS*            cons,               /**< constraint */
4433 	   SCIP_HASHMAP*         exprmap,            /**< map to remember generated variables for visited product expressions */
4434 	   SCIP_EXPRITER*        it,                 /**< expression iterator */
4435 	   int*                  naddconss,          /**< pointer to update the total number of added constraints (might be NULL) */
4436 	   int*                  nchgcoefs           /**< pointer to update the total number of changed coefficients (might be NULL) */
4437 	   )
4438 	{
4439 	   SCIP_CONSHDLRDATA* conshdlrdata;
4440 	   SCIP_CONSDATA* consdata;
4441 	   SCIP_EXPR* expr;
4442 	
4443 	   assert(conshdlr != NULL);
4444 	   assert(cons != NULL);
4445 	   assert(exprmap != NULL);
4446 	   assert(it != NULL);
4447 	
4448 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4449 	   assert(conshdlrdata != NULL);
4450 	
4451 	   consdata = SCIPconsGetData(cons);
4452 	   assert(consdata != NULL);
4453 	   assert(consdata->expr != NULL);
4454 	
4455 	   SCIPdebugMsg(scip, "  check constraint %s\n", SCIPconsGetName(cons));
4456 	
4457 	   for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4458 	   {
4459 	      SCIP_EXPR* newexpr = NULL;
4460 	      SCIP_EXPR* childexpr;
4461 	      int childexpridx;
4462 	
4463 	      childexpridx = SCIPexpriterGetChildIdxDFS(it);
4464 	      assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4465 	      childexpr = SCIPexpriterGetChildExprDFS(it);
4466 	      assert(childexpr != NULL);
4467 	
4468 	      /* try to factorize variables in a sum expression that contains several products of binary variables */
4469 	      if( conshdlrdata->reformbinprodsfac > 1 )
4470 	      {
4471 	         SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4472 	      }
4473 	
4474 	      /* try to create an expression that represents a product of binary variables */
4475 	      if( newexpr == NULL )
4476 	      {
4477 	         SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4478 	      }
4479 	
4480 	      if( newexpr != NULL )
4481 	      {
4482 	         assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4483 	
4484 	         /* replace product expression */
4485 	         SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4486 	
4487 	         /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4488 	         SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4489 	
4490 	         /* mark the constraint to not be simplified anymore */
4491 	         consdata->issimplified = FALSE;
4492 	      }
4493 	   }
4494 	
4495 	   return SCIP_OKAY;
4496 	}
4497 	
4498 	/** reformulates products of binary variables during presolving in the following way:
4499 	 *
4500 	 * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4501 	 * 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}:
4502 	 * \f[
4503 	 *    z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4504 	 * \f]
4505 	 *
4506 	 * 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$.
4507 	 * These cliques allow for a better reformulation. There are four cases:
4508 	 *
4509 	 *    1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4510 	 *    2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4511 	 *    3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4512 	 *    4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4513 	 *
4514 	 * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4515 	 *
4516 	 * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4517 	 * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4518 	 * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4519 	 * Such a lower sum is reformulated with only one extra variable w_i:
4520 	 * \f{align}{
4521 	 *    \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4522 	 *    \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4523 	 *    \text{minact}\, x_i & \leq w_i, \\
4524 	 *    w_i &\leq \text{maxact}\, x_i, \\
4525 	 *    \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4526 	 *    \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4527 	 * \f}
4528 	 * 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
4529 	 * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4530 	 * of terms are prioritized.
4531 	 */
4532 	static
4533 	SCIP_RETCODE presolveBinaryProducts(
4534 	   SCIP*                 scip,               /**< SCIP data structure */
4535 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4536 	   SCIP_CONS**           conss,              /**< constraints */
4537 	   int                   nconss,             /**< total number of constraints */
4538 	   int*                  naddconss,          /**< pointer to store the total number of added constraints (might be NULL) */
4539 	   int*                  nchgcoefs           /**< pointer to store the total number of changed coefficients (might be NULL) */
4540 	   )
4541 	{
4542 	   SCIP_CONSHDLRDATA* conshdlrdata;
4543 	   SCIP_HASHMAP* exprmap;
4544 	   SCIP_EXPRITER* it;
4545 	   int c;
4546 	
4547 	   assert(conshdlr != NULL);
4548 	
4549 	   /* no nonlinear constraints or binary variables -> skip */
4550 	   if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4551 	      return SCIP_OKAY;
4552 	   assert(conss != NULL);
4553 	
4554 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4555 	   assert(conshdlrdata != NULL);
4556 	
4557 	   /* create expression hash map */
4558 	   SCIP_CALL( SCIPhashmapCreate(&exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
4559 	
4560 	   /* create expression iterator */
4561 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4562 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4563 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
4564 	
4565 	   SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4566 	
4567 	   for( c = 0; c < nconss; ++c )
4568 	   {
4569 	      SCIP_CONSDATA* consdata;
4570 	      SCIP_EXPR* newexpr = NULL;
4571 	
4572 	      assert(conss[c] != NULL);
4573 	
4574 	      consdata = SCIPconsGetData(conss[c]);
4575 	      assert(consdata != NULL);
4576 	
4577 	      /* try to reformulate the root expression */
4578 	      if( conshdlrdata->reformbinprodsfac > 1 )
4579 	      {
4580 	         SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4581 	      }
4582 	
4583 	      /* release the root node if another expression has been found */
4584 	      if( newexpr != NULL )
4585 	      {
4586 	         SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4587 	         consdata->expr = newexpr;
4588 	
4589 	         /* mark constraint to be not simplified anymore */
4590 	         consdata->issimplified = FALSE;
4591 	      }
4592 	
4593 	      /* replace each product of binary variables separately */
4594 	      SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4595 	   }
4596 	
4597 	   /* free memory */
4598 	   SCIPhashmapFree(&exprmap);
4599 	   SCIPfreeExpriter(&it);
4600 	
4601 	   return SCIP_OKAY;
4602 	}
4603 	
4604 	/** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4605 	 *
4606 	 *  Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4607 	 *  Then scale by -1 if
4608 	 *  - \f$n_+ < n_-\f$, or
4609 	 *  - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4610 	 */
4611 	static
4612 	SCIP_RETCODE scaleConsSides(
4613 	   SCIP*                 scip,               /**< SCIP data structure */
4614 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
4615 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
4616 	   SCIP_Bool*            changed             /**< buffer to store if the expression of cons changed */
4617 	   )
4618 	{
4619 	   SCIP_CONSDATA* consdata;
4620 	   int i;
4621 	
4622 	   assert(cons != NULL);
4623 	
4624 	   consdata = SCIPconsGetData(cons);
4625 	   assert(consdata != NULL);
4626 	
4627 	   if( SCIPisExprSum(scip, consdata->expr) )
4628 	   {
4629 	      SCIP_Real* coefs;
4630 	      SCIP_Real constant;
4631 	      int nchildren;
4632 	      int counter = 0;
4633 	
4634 	      coefs = SCIPgetCoefsExprSum(consdata->expr);
4635 	      constant = SCIPgetConstantExprSum(consdata->expr);
4636 	      nchildren = SCIPexprGetNChildren(consdata->expr);
4637 	
4638 	      /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4639 	      if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4640 	      {
4641 	         SCIP_EXPR* expr;
4642 	         expr = consdata->expr;
4643 	
4644 	         consdata->expr = SCIPexprGetChildren(expr)[0];
4645 	         assert(!SCIPisExprSum(scip, consdata->expr));
4646 	
4647 	         SCIPcaptureExpr(consdata->expr);
4648 	
4649 	         SCIPswapReals(&consdata->lhs, &consdata->rhs);
4650 	         consdata->lhs = -consdata->lhs;
4651 	         consdata->rhs = -consdata->rhs;
4652 	
4653 	         SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4654 	         *changed = TRUE;
4655 	         return SCIP_OKAY;
4656 	      }
4657 	
4658 	      /* compute n_+ - n_i */
4659 	      for( i = 0; i < nchildren; ++i )
4660 	         counter += coefs[i] > 0 ? 1 : -1;
4661 	
4662 	      if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4663 	      {
4664 	         SCIP_EXPR* expr;
4665 	         SCIP_Real* newcoefs;
4666 	
4667 	         /* allocate memory */
4668 	         SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4669 	
4670 	         for( i = 0; i < nchildren; ++i )
4671 	            newcoefs[i] = -coefs[i];
4672 	
4673 	         /* create a new sum expression */
4674 	         SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4675 	
4676 	         /* replace expression in constraint data and scale sides */
4677 	         SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4678 	         consdata->expr = expr;
4679 	         SCIPswapReals(&consdata->lhs, &consdata->rhs);
4680 	         consdata->lhs = -consdata->lhs;
4681 	         consdata->rhs = -consdata->rhs;
4682 	
4683 	         /* free memory */
4684 	         SCIPfreeBufferArray(scip, &newcoefs);
4685 	
4686 	         *changed = TRUE;
4687 	      }
4688 	   }
4689 	
4690 	   return SCIP_OKAY;
4691 	}
4692 	
4693 	/** forbid multiaggrations of variables that appear nonlinear in constraints */
4694 	static
4695 	SCIP_RETCODE forbidNonlinearVariablesMultiaggration(
4696 	   SCIP*                 scip,               /**< SCIP data structure */
4697 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4698 	   SCIP_CONS**           conss,              /**< constraints */
4699 	   int                   nconss              /**< number of constraints */
4700 	   )
4701 	{
4702 	   SCIP_EXPRITER* it;
4703 	   SCIP_CONSDATA* consdata;
4704 	   SCIP_EXPR* expr;
4705 	   int c;
4706 	
4707 	   assert(scip != NULL);
4708 	   assert(conshdlr != NULL);
4709 	
4710 	   if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4711 	      return SCIP_OKAY;
4712 	
4713 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4714 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
4715 	
4716 	   for( c = 0; c < nconss; ++c )
4717 	   {
4718 	      consdata = SCIPconsGetData(conss[c]);
4719 	      assert(consdata != NULL);
4720 	
4721 	      /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4722 	       *   i.e., skip children of sum that are variables
4723 	       */
4724 	      if( SCIPisExprSum(scip, consdata->expr) )
4725 	      {
4726 	         int i;
4727 	         SCIP_EXPR* child;
4728 	         for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4729 	         {
4730 	            child = SCIPexprGetChildren(consdata->expr)[i];
4731 	
4732 	            /* skip variable expression, as they correspond to a linear term */
4733 	            if( SCIPisExprVar(scip, child) )
4734 	               continue;
4735 	
4736 	            for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4737 	               if( SCIPisExprVar(scip, expr) )
4738 	               {
4739 	                  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPgetVarExprVar(expr)) );
4740 	               }
4741 	         }
4742 	      }
4743 	      else
4744 	      {
4745 	         for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4746 	            if( SCIPisExprVar(scip, expr) )
4747 	            {
4748 	               SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPgetVarExprVar(expr)) );
4749 	            }
4750 	      }
4751 	   }
4752 	
4753 	   SCIPfreeExpriter(&it);
4754 	
4755 	   return SCIP_OKAY;
4756 	}
4757 	
4758 	/** simplifies expressions and replaces common subexpressions for a set of constraints
4759 	 * @todo put the constant to the constraint sides
4760 	 */
4761 	static
4762 	SCIP_RETCODE canonicalizeConstraints(
4763 	   SCIP*                 scip,               /**< SCIP data structure */
4764 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
4765 	   SCIP_CONS**           conss,              /**< constraints */
4766 	   int                   nconss,             /**< total number of constraints */
4767 	   SCIP_PRESOLTIMING     presoltiming,       /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4768 	   SCIP_Bool*            infeasible,         /**< buffer to store whether infeasibility has been detected */
4769 	   int*                  ndelconss,          /**< counter to add number of deleted constraints, or NULL */
4770 	   int*                  naddconss,          /**< counter to add number of added constraints, or NULL */
4771 	   int*                  nchgcoefs           /**< counter to add number of changed coefficients, or NULL */
4772 	   )
4773 	{
4774 	   SCIP_CONSHDLRDATA* conshdlrdata;
4775 	   SCIP_CONSDATA* consdata;
4776 	   int* nlockspos;
4777 	   int* nlocksneg;
4778 	   SCIP_Bool havechange;
4779 	   int i;
4780 	
4781 	   assert(scip != NULL);
4782 	   assert(conshdlr != NULL);
4783 	   assert(conss != NULL);
4784 	   assert(nconss > 0);
4785 	   assert(infeasible != NULL);
4786 	
4787 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
4788 	   assert(conshdlrdata != NULL);
4789 	
4790 	   /* update number of canonicalize calls */
4791 	   ++(conshdlrdata->ncanonicalizecalls);
4792 	
4793 	   SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4794 	
4795 	   *infeasible = FALSE;
4796 	
4797 	   /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4798 	   havechange = conshdlrdata->ncanonicalizecalls == 1;
4799 	
4800 	   /* free nonlinear handlers information from expressions */  /* TODO can skip this in first presolve round */
4801 	   SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4802 	
4803 	   /* allocate memory for storing locks of each constraint */
4804 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4805 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4806 	
4807 	   /* unlock all constraints */
4808 	   for( i = 0; i < nconss; ++i )
4809 	   {
4810 	      assert(conss[i] != NULL);
4811 	
4812 	      consdata = SCIPconsGetData(conss[i]);
4813 	      assert(consdata != NULL);
4814 	
4815 	      /* remember locks */
4816 	      nlockspos[i] = consdata->nlockspos;
4817 	      nlocksneg[i] = consdata->nlocksneg;
4818 	
4819 	      /* remove locks */
4820 	      SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4821 	      assert(consdata->nlockspos == 0);
4822 	      assert(consdata->nlocksneg == 0);
4823 	   }
4824 	
4825 	#ifndef NDEBUG
4826 	   /* check whether all locks of each expression have been removed */
4827 	   for( i = 0; i < nconss; ++i )
4828 	   {
4829 	      SCIP_EXPR* expr;
4830 	      SCIP_EXPRITER* it;
4831 	
4832 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4833 	
4834 	      consdata = SCIPconsGetData(conss[i]);
4835 	      assert(consdata != NULL);
4836 	
4837 	      SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_RTOPOLOGIC, TRUE) );
4838 	      for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4839 	      {
4840 	         assert(expr != NULL);
4841 	         assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4842 	         assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4843 	      }
4844 	      SCIPfreeExpriter(&it);
4845 	   }
4846 	#endif
4847 	
4848 	   /* reformulate products of binary variables */
4849 	   if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4850 	      && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4851 	   {
4852 	      int tmpnaddconss = 0;
4853 	      int tmpnchgcoefs = 0;
4854 	
4855 	      /* call this function before simplification because expressions might not be simplified after reformulating
4856 	       * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4857 	       */
4858 	      SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4859 	
4860 	      /* update counters */
4861 	      if( naddconss != NULL )
4862 	         *naddconss = tmpnaddconss;
4863 	      if( nchgcoefs != NULL )
4864 	         *nchgcoefs = tmpnchgcoefs;
4865 	
4866 	      /* check whether at least one expression has changed */
4867 	      if( tmpnaddconss + tmpnchgcoefs > 0 )
4868 	         havechange = TRUE;
4869 	   }
4870 	
4871 	   for( i = 0; i < nconss; ++i )
4872 	   {
4873 	      consdata = SCIPconsGetData(conss[i]);
4874 	      assert(consdata != NULL);
4875 	
4876 	      /* call simplify for each expression */
4877 	      if( !consdata->issimplified && consdata->expr != NULL )
4878 	      {
4879 	         SCIP_EXPR* simplified;
4880 	         SCIP_Bool changed;
4881 	
4882 	         changed = FALSE;
4883 	         SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4884 	         consdata->issimplified = TRUE;
4885 	
4886 	         if( changed )
4887 	            havechange = TRUE;
4888 	
4889 	         /* 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").
4890 	          * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4891 	          */
4892 	         if( simplified != consdata->expr )
4893 	         {
4894 	            assert(changed);
4895 	
4896 	            /* release old expression */
4897 	            SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4898 	
4899 	            /* store simplified expression */
4900 	            consdata->expr = simplified;
4901 	         }
4902 	         else
4903 	         {
4904 	            /* The simplify captures simplified in any case, also if nothing has changed.
4905 	             * Therefore, we have to release it here.
4906 	             */
4907 	            SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
4908 	         }
4909 	
4910 	         if( *infeasible )
4911 	            break;
4912 	
4913 	         /* scale constraint sides */
4914 	         SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
4915 	
4916 	         if( changed )
4917 	            havechange = TRUE;
4918 	
4919 	         /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4920 	         if( SCIPisExprValue(scip, consdata->expr) )
4921 	         {
4922 	            SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
4923 	            if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
4924 	                (!SCIPisInfinity(scip,  consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
4925 	            {
4926 	               SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
4927 	               SCIPdebugPrintCons(scip, conss[i], NULL);
4928 	               *infeasible = TRUE;
4929 	               break;
4930 	            }
4931 	            else
4932 	            {
4933 	               SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
4934 	               SCIP_CALL( SCIPdelCons(scip, conss[i]) );
4935 	               if( ndelconss != NULL )
4936 	                  ++*ndelconss;
4937 	               havechange = TRUE;
4938 	            }
4939 	         }
4940 	      }
4941 	   }
4942 	
4943 	   /* replace common subexpressions */
4944 	   if( havechange && !*infeasible )
4945 	   {
4946 	      SCIP_CONS** consssorted;
4947 	      SCIP_EXPR** rootexprs;
4948 	      SCIP_Bool replacedroot;
4949 	
4950 	      SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
4951 	      for( i = 0; i < nconss; ++i )
4952 	         rootexprs[i] = SCIPconsGetData(conss[i])->expr;
4953 	
4954 	      SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
4955 	
4956 	      /* update pointer to root expr in constraints, if any has changed
4957 	       * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
4958 	       */
4959 	      if( replacedroot )
4960 	         for( i = 0; i < nconss; ++i )
4961 	            SCIPconsGetData(conss[i])->expr = rootexprs[i];
4962 	
4963 	      SCIPfreeBufferArray(scip, &rootexprs);
4964 	
4965 	      /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
4966 	       * been changed after simplification; now we completely recollect all variable expression and variable events
4967 	       */
4968 	
4969 	      /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
4970 	       * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
4971 	       */
4972 	      SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
4973 	      SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
4974 	
4975 	      for( i = nconss-1; i >= 0; --i )
4976 	      {
4977 	         assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
4978 	         if( SCIPconsIsDeleted(consssorted[i]) )
4979 	            continue;
4980 	
4981 	         SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
4982 	         SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
4983 	      }
4984 	      for( i = 0; i < nconss; ++i )
4985 	      {
4986 	         if( SCIPconsIsDeleted(consssorted[i]) )
4987 	            continue;
4988 	
4989 	         SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
4990 	         SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
4991 	      }
4992 	
4993 	      SCIPfreeBufferArray(scip, &consssorted);
4994 	
4995 	      /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
4996 	       * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
4997 	       * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
4998 	       */
4999 	      SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5000 	   }
5001 	
5002 	   /* restore locks */
5003 	   for( i = 0; i < nconss; ++i )
5004 	   {
5005 	      if( SCIPconsIsDeleted(conss[i]) )
5006 	         continue;
5007 	
5008 	      SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5009 	   }
5010 	
5011 	   /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5012 	    * TODO can we skip this in presoltiming fast?
5013 	    */
5014 	   if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5015 	   {
5016 	      /* reset one of the number of detections counter to count only current presolving round */
5017 	      for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5018 	         SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5019 	
5020 	      SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5021 	   }
5022 	
5023 	   /* free allocated memory */
5024 	   SCIPfreeBufferArray(scip, &nlocksneg);
5025 	   SCIPfreeBufferArray(scip, &nlockspos);
5026 	
5027 	   SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5028 	
5029 	   return SCIP_OKAY;
5030 	}
5031 	
5032 	/** merges constraints that have the same root expression */
5033 	static
5034 	SCIP_RETCODE presolveMergeConss(
5035 	   SCIP*                 scip,               /**< SCIP data structure */
5036 	   SCIP_CONS**           conss,              /**< constraints to process */
5037 	   int                   nconss,             /**< number of constraints */
5038 	   SCIP_Bool*            success             /**< pointer to store whether at least one constraint could be deleted */
5039 	   )
5040 	{
5041 	   SCIP_HASHMAP* expr2cons;
5042 	   SCIP_Bool* updatelocks;
5043 	   int* nlockspos;
5044 	   int* nlocksneg;
5045 	   int c;
5046 	
5047 	   assert(success != NULL);
5048 	
5049 	   *success = FALSE;
5050 	
5051 	   /* not enough constraints available */
5052 	   if( nconss <= 1 )
5053 	      return SCIP_OKAY;
5054 	
5055 	   SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5056 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5057 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5058 	   SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5059 	
5060 	   for( c = 0; c < nconss; ++c )
5061 	   {
5062 	      SCIP_CONSDATA* consdata;
5063 	
5064 	      /* ignore deleted constraints */
5065 	      if( SCIPconsIsDeleted(conss[c]) )
5066 	         continue;
5067 	
5068 	      consdata = SCIPconsGetData(conss[c]);
5069 	      assert(consdata != NULL);
5070 	
5071 	      /* add expression to the hash map if not seen so far */
5072 	      if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5073 	      {
5074 	         SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5075 	      }
5076 	      else
5077 	      {
5078 	         SCIP_CONSDATA* imgconsdata;
5079 	         int idx;
5080 	
5081 	         idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5082 	         assert(idx >= 0 && idx < nconss);
5083 	
5084 	         imgconsdata = SCIPconsGetData(conss[idx]);
5085 	         assert(imgconsdata != NULL);
5086 	         assert(imgconsdata->expr == consdata->expr);
5087 	
5088 	         SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5089 	            SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5090 	
5091 	         /* check whether locks need to be updated */
5092 	         if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5093 	            || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5094 	         {
5095 	            nlockspos[idx] = imgconsdata->nlockspos;
5096 	            nlocksneg[idx] = imgconsdata->nlocksneg;
5097 	            SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5098 	            updatelocks[idx] = TRUE;
5099 	         }
5100 	
5101 	         /* update constraint sides */
5102 	         imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5103 	         imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5104 	
5105 	         /* delete constraint */
5106 	         SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5107 	         *success = TRUE;
5108 	      }
5109 	   }
5110 	
5111 	   /* restore locks of updated constraints */
5112 	   if( *success )
5113 	   {
5114 	      for( c = 0; c < nconss; ++c )
5115 	      {
5116 	         if( updatelocks[c] )
5117 	         {
5118 	            SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5119 	         }
5120 	      }
5121 	   }
5122 	
5123 	   /* free memory */
5124 	   SCIPfreeBufferArray(scip, &nlocksneg);
5125 	   SCIPfreeBufferArray(scip, &nlockspos);
5126 	   SCIPfreeBufferArray(scip, &updatelocks);
5127 	   SCIPhashmapFree(&expr2cons);
5128 	
5129 	   return SCIP_OKAY;
5130 	}
5131 	
5132 	/** interval evaluation of variables as used in redundancy check
5133 	 *
5134 	 * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5135 	 */
5136 	static
5137 	SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5138 	{  /*lint --e{715}*/
5139 	   SCIP_CONSHDLRDATA* conshdlrdata;
5140 	   SCIP_INTERVAL interval;
5141 	   SCIP_Real lb;
5142 	   SCIP_Real ub;
5143 	
5144 	   assert(scip != NULL);
5145 	   assert(var != NULL);
5146 	
5147 	   conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5148 	   assert(conshdlrdata != NULL);
5149 	
5150 	   if( conshdlrdata->globalbounds )
5151 	   {
5152 	      lb = SCIPvarGetLbGlobal(var);
5153 	      ub = SCIPvarGetUbGlobal(var);
5154 	   }
5155 	   else
5156 	   {
5157 	      lb = SCIPvarGetLbLocal(var);
5158 	      ub = SCIPvarGetUbLocal(var);
5159 	   }
5160 	   assert(lb <= ub);  /* can SCIP ensure by now that variable bounds are not contradicting? */
5161 	
5162 	   /* relax variable bounds, if there are bounds and variable is not fixed
5163 	    * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5164 	    */
5165 	   if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5166 	   {
5167 	      if( !SCIPisInfinity(scip, -lb) )
5168 	         lb -= SCIPfeastol(scip);
5169 	
5170 	      if( !SCIPisInfinity(scip, ub) )
5171 	         ub += SCIPfeastol(scip);
5172 	   }
5173 	
5174 	   /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5175 	   lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
5176 	   ub =  infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY,  ub);
5177 	   assert(lb <= ub);
5178 	
5179 	   SCIPintervalSetBounds(&interval, lb, ub);
5180 	
5181 	   return interval;
5182 	}
5183 	
5184 	/** removes constraints that are always feasible or very simple
5185 	 *
5186 	 * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5187 	 * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5188 	 * might violate variable bounds by up to feastol, too.
5189 	 * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5190 	 *
5191 	 * Also removes constraints of the form lhs &le; variable &le; rhs.
5192 	 *
5193 	 * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5194 	 *
5195 	 * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5196 	 * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5197 	 * would appear as if the constraint is redundant.
5198 	 */
5199 	static
5200 	SCIP_RETCODE presolveRedundantConss(
5201 	   SCIP*                 scip,               /**< SCIP data structure */
5202 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
5203 	   SCIP_CONS**           conss,              /**< constraints to propagate */
5204 	   int                   nconss,             /**< total number of constraints */
5205 	   SCIP_Bool*            cutoff,             /**< pointer to store whether infeasibility has been identified */
5206 	   int*                  ndelconss,          /**< buffer to add the number of deleted constraints */
5207 	   int*                  nchgbds             /**< buffer to add the number of variable bound tightenings */
5208 	   )
5209 	{
5210 	   SCIP_CONSHDLRDATA* conshdlrdata;
5211 	   SCIP_CONSDATA* consdata;
5212 	   SCIP_INTERVAL activity;
5213 	   SCIP_INTERVAL sides;
5214 	   int i;
5215 	
5216 	   assert(scip != NULL);
5217 	   assert(conshdlr != NULL);
5218 	   assert(conss != NULL);
5219 	   assert(nconss >= 0);
5220 	   assert(cutoff != NULL);
5221 	   assert(ndelconss != NULL);
5222 	   assert(nchgbds != NULL);
5223 	
5224 	   /* no constraints to check */
5225 	   if( nconss == 0 )
5226 	      return SCIP_OKAY;
5227 	
5228 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
5229 	   assert(conshdlrdata != NULL);
5230 	
5231 	   /* increase curboundstag and set lastvaractivitymethodchange
5232 	    * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5233 	    * for the redundancy check differently than for domain propagation
5234 	    * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5235 	    */
5236 	   ++conshdlrdata->curboundstag;
5237 	   assert(conshdlrdata->curboundstag > 0);
5238 	   conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5239 	   conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5240 	   conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5241 	
5242 	   SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5243 	
5244 	   *cutoff = FALSE;
5245 	   for( i = 0; i < nconss; ++i )
5246 	   {
5247 	      if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5248 	         continue;
5249 	
5250 	      consdata = SCIPconsGetData(conss[i]);
5251 	      assert(consdata != NULL);
5252 	
5253 	      /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5254 	      if( SCIPisExprValue(scip, consdata->expr) )
5255 	      {
5256 	         SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5257 	
5258 	         if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5259 	             (!SCIPisInfinity(scip,  consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5260 	         {
5261 	            SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5262 	            *cutoff = TRUE;
5263 	
5264 	            goto TERMINATE;
5265 	         }
5266 	
5267 	         SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5268 	
5269 	         SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5270 	         ++*ndelconss;
5271 	
5272 	         continue;
5273 	      }
5274 	
5275 	      /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5276 	      if( SCIPisExprVar(scip, consdata->expr) )
5277 	      {
5278 	         SCIP_VAR* var;
5279 	         SCIP_Bool tightened;
5280 	
5281 	         var = SCIPgetVarExprVar(consdata->expr);
5282 	         assert(var != NULL);
5283 	
5284 	         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);
5285 	
5286 	         /* ensure that variable bounds are within constraint sides */
5287 	         if( !SCIPisInfinity(scip, -consdata->lhs) )
5288 	         {
5289 	            SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5290 	
5291 	            if( tightened )
5292 	               ++*nchgbds;
5293 	
5294 	            if( *cutoff )
5295 	               goto TERMINATE;
5296 	         }
5297 	
5298 	         if( !SCIPisInfinity(scip, consdata->rhs) )
5299 	         {
5300 	            SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5301 	
5302 	            if( tightened )
5303 	               ++*nchgbds;
5304 	
5305 	            if( *cutoff )
5306 	               goto TERMINATE;
5307 	         }
5308 	
5309 	         /* delete the (now) redundant constraint locally */
5310 	         SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5311 	         ++*ndelconss;
5312 	
5313 	         continue;
5314 	      }
5315 	
5316 	      /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5317 	       * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5318 	       * variable bounds by up to feastol
5319 	       * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5320 	       */
5321 	      SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5322 	      SCIPdebugPrintCons(scip, conss[i], NULL);
5323 	
5324 	      SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5325 	      assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5326 	
5327 	      /* it is unlikely that we detect infeasibility by doing forward propagation */
5328 	      if( *cutoff )
5329 	      {
5330 	         SCIPdebugMsg(scip, " -> cutoff\n");
5331 	         goto TERMINATE;
5332 	      }
5333 	
5334 	      assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5335 	      activity = SCIPexprGetActivity(consdata->expr);
5336 	
5337 	      /* relax sides by feastol
5338 	       * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5339 	       */
5340 	      SCIPintervalSetBounds(&sides,
5341 	         SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5342 	         SCIPisInfinity(scip,  consdata->rhs) ?  SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5343 	
5344 	      if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5345 	      {
5346 	         SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5347 	
5348 	         SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5349 	         ++*ndelconss;
5350 	
5351 	         continue;
5352 	      }
5353 	
5354 	      SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5355 	   }
5356 	
5357 	TERMINATE:
5358 	   /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5359 	   ++conshdlrdata->curboundstag;
5360 	   conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5361 	   conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5362 	   conshdlrdata->intevalvar = intEvalVarBoundTightening;
5363 	
5364 	   return SCIP_OKAY;
5365 	}
5366 	
5367 	/** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5368 	static
5369 	SCIP_RETCODE presolveUpgrade(
5370 	   SCIP*                 scip,               /**< SCIP data structure */
5371 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler data structure */
5372 	   SCIP_CONS*            cons,               /**< source constraint to try to convert */
5373 	   SCIP_Bool*            upgraded,           /**< buffer to store whether constraint was upgraded */
5374 	   int*                  nupgdconss,         /**< buffer to increase if constraint was upgraded */
5375 	   int*                  naddconss           /**< buffer to increase with number of additional constraints created during upgrade */
5376 	   )
5377 	{
5378 	   SCIP_CONSHDLRDATA* conshdlrdata;
5379 	   SCIP_CONSDATA* consdata;
5380 	   SCIP_CONS** upgdconss;
5381 	   int upgdconsssize;
5382 	   int nupgdconss_;
5383 	   int i;
5384 	
5385 	   assert(scip != NULL);
5386 	   assert(conshdlr != NULL);
5387 	   assert(cons != NULL);
5388 	   assert(!SCIPconsIsModifiable(cons));
5389 	   assert(upgraded   != NULL);
5390 	   assert(nupgdconss != NULL);
5391 	   assert(naddconss  != NULL);
5392 	
5393 	   *upgraded = FALSE;
5394 	
5395 	   nupgdconss_ = 0;
5396 	
5397 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
5398 	   assert(conshdlrdata != NULL);
5399 	
5400 	   /* if there are no upgrade methods, we can stop */
5401 	   if( conshdlrdata->nconsupgrades == 0 )
5402 	      return SCIP_OKAY;
5403 	
5404 	   upgdconsssize = 2;
5405 	   SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5406 	
5407 	   /* call the upgrading methods */
5408 	   SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5409 	   SCIPdebugPrintCons(scip, cons, NULL);
5410 	
5411 	   consdata = SCIPconsGetData(cons);
5412 	   assert(consdata != NULL);
5413 	
5414 	   /* try all upgrading methods in priority order in case the upgrading step is enable  */
5415 	   for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5416 	   {
5417 	      if( !conshdlrdata->consupgrades[i]->active )
5418 	         continue;
5419 	
5420 	      assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5421 	
5422 	      SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5423 	
5424 	      while( nupgdconss_ < 0 )
5425 	      {
5426 	         /* upgrade function requires more memory: resize upgdconss and call again */
5427 	         assert(-nupgdconss_ > upgdconsssize);
5428 	         upgdconsssize = -nupgdconss_;
5429 	         SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5430 	
5431 	         SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5432 	
5433 	         assert(nupgdconss_ != 0);
5434 	      }
5435 	
5436 	      if( nupgdconss_ > 0 )
5437 	      {
5438 	         /* got upgrade */
5439 	         int j;
5440 	
5441 	         SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5442 	
5443 	         /* add the upgraded constraints to the problem and forget them */
5444 	         for( j = 0; j < nupgdconss_; ++j )
5445 	         {
5446 	            SCIPdebugMsgPrint(scip, "\t");
5447 	            SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5448 	
5449 	            SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) );      /*lint !e613*/
5450 	            SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5451 	         }
5452 	
5453 	         /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5454 	         *nupgdconss += 1;
5455 	         *naddconss += nupgdconss_ - 1;
5456 	         *upgraded = TRUE;
5457 	
5458 	         /* delete upgraded constraint */
5459 	         SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5460 	         SCIP_CALL( SCIPdelCons(scip, cons) );
5461 	
5462 	         break;
5463 	      }
5464 	   }
5465 	
5466 	   SCIPfreeBufferArray(scip, &upgdconss);
5467 	
5468 	   return SCIP_OKAY;
5469 	}
5470 	
5471 	/** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5472 	 *  the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5473 	 *  variable bounds, and is not binary
5474 	 */
5475 	static
5476 	SCIP_Bool isSingleLockedCand(
5477 	   SCIP*                 scip,               /**< SCIP data structure */
5478 	   SCIP_EXPR*            expr                /**< variable expression */
5479 	   )
5480 	{
5481 	   SCIP_VAR* var;
5482 	   SCIP_EXPR_OWNERDATA* ownerdata;
5483 	
5484 	   assert(SCIPisExprVar(scip, expr));
5485 	
5486 	   var = SCIPgetVarExprVar(expr);
5487 	   assert(var != NULL);
5488 	
5489 	   ownerdata = SCIPexprGetOwnerData(expr);
5490 	   assert(ownerdata != NULL);
5491 	
5492 	   return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5493 	      && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5494 	      && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5495 	      && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5496 	      && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY
5497 	      && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5498 	}
5499 	
5500 	/** removes all variable expressions that are contained in a given expression from a hash map */
5501 	static
5502 	SCIP_RETCODE removeSingleLockedVars(
5503 	   SCIP*                 scip,               /**< SCIP data structure */
5504 	   SCIP_EXPR*            expr,               /**< expression */
5505 	   SCIP_EXPRITER*        it,                 /**< expression iterator */
5506 	   SCIP_HASHMAP*         exprcands           /**< map to hash variable expressions */
5507 	   )
5508 	{
5509 	   SCIP_EXPR* e;
5510 	
5511 	   for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5512 	   {
5513 	      if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5514 	      {
5515 	         SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5516 	      }
5517 	   }
5518 	
5519 	   return SCIP_OKAY;
5520 	}
5521 	
5522 	/** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5523 	 *  nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5524 	 *
5525 	 *  If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5526 	 *  Otherwise, a bound disjunction constraint is added.
5527 	 *
5528 	 *  @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
5529 	 *  @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5530 	 *    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
5531 	 *    on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5532 	 */
5533 	static
5534 	SCIP_RETCODE presolveSingleLockedVars(
5535 	   SCIP*                 scip,               /**< SCIP data structure */
5536 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
5537 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
5538 	   int*                  nchgvartypes,       /**< pointer to store the total number of changed variable types */
5539 	   int*                  naddconss,          /**< pointer to store the total number of added constraints */
5540 	   SCIP_Bool*            infeasible          /**< pointer to store whether problem is infeasible */
5541 	   )
5542 	{
5543 	   SCIP_CONSHDLRDATA* conshdlrdata;
5544 	   SCIP_CONSDATA* consdata;
5545 	   SCIP_EXPR** singlelocked;
5546 	   SCIP_HASHMAP* exprcands;
5547 	   SCIP_Bool hasbounddisj;
5548 	   SCIP_Bool haslhs;
5549 	   SCIP_Bool hasrhs;
5550 	   int nsinglelocked = 0;
5551 	   int i;
5552 	
5553 	   assert(conshdlr != NULL);
5554 	   assert(cons != NULL);
5555 	   assert(nchgvartypes != NULL);
5556 	   assert(naddconss != NULL);
5557 	   assert(infeasible != NULL);
5558 	
5559 	   *nchgvartypes = 0;
5560 	   *naddconss = 0;
5561 	   *infeasible = FALSE;
5562 	
5563 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
5564 	   assert(conshdlrdata != NULL);
5565 	   consdata = SCIPconsGetData(cons);
5566 	   assert(consdata != NULL);
5567 	
5568 	   /* only consider constraints with one finite side */
5569 	   if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5570 	      return SCIP_OKAY;
5571 	
5572 	   /* only consider sum expressions */
5573 	   if( !SCIPisExprSum(scip, consdata->expr) )
5574 	      return SCIP_OKAY;
5575 	
5576 	   /* remember which side is finite */
5577 	   haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5578 	   hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5579 	
5580 	   /* allocate memory */
5581 	   SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5582 	   SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5583 	
5584 	   /* check all variable expressions for single locked variables */
5585 	   for( i = 0; i < consdata->nvarexprs; ++i )
5586 	   {
5587 	      assert(consdata->varexprs[i] != NULL);
5588 	
5589 	      if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5590 	      {
5591 	         SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5592 	         singlelocked[nsinglelocked++] = consdata->varexprs[i];
5593 	      }
5594 	   }
5595 	   SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5596 	
5597 	   if( nsinglelocked > 0 )
5598 	   {
5599 	      SCIP_EXPR** children;
5600 	      SCIP_EXPRITER* it;
5601 	      int nchildren;
5602 	
5603 	      children = SCIPexprGetChildren(consdata->expr);
5604 	      nchildren = SCIPexprGetNChildren(consdata->expr);
5605 	
5606 	      /* create iterator */
5607 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
5608 	      SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
5609 	      SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR);
5610 	
5611 	      for( i = 0; i < nchildren; ++i )
5612 	      {
5613 	         SCIP_EXPR* child;
5614 	         SCIP_Real coef;
5615 	
5616 	         child = children[i];
5617 	         assert(child != NULL);
5618 	         coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5619 	
5620 	         /* ignore linear terms */
5621 	         if( SCIPisExprVar(scip, child) )
5622 	            continue;
5623 	
5624 	         /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5625 	          * expression that represents f_j and remove each variable expression from exprcands
5626 	          */
5627 	         else if( SCIPisExprProduct(scip, child) )
5628 	         {
5629 	            int j;
5630 	
5631 	            for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5632 	            {
5633 	               SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5634 	
5635 	               if( !SCIPisExprVar(scip, grandchild) )
5636 	               {
5637 	                  /* mark all variable expressions that are contained in the expression */
5638 	                  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5639 	               }
5640 	            }
5641 	         }
5642 	         /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5643 	          * for an integer k >= 1
5644 	          */
5645 	         else if( SCIPisExprPower(scip, child) )
5646 	         {
5647 	            SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5648 	            SCIP_Real exponent = SCIPgetExponentExprPow(child);
5649 	            SCIP_Bool valid;
5650 	
5651 	            /* check for even integral exponent */
5652 	            valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5653 	
5654 	            if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5655 	            {
5656 	               /* mark all variable expressions that are contained in the expression */
5657 	               SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5658 	            }
5659 	         }
5660 	         /* all other cases cannot be handled */
5661 	         else
5662 	         {
5663 	            /* mark all variable expressions that are contained in the expression */
5664 	            SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5665 	         }
5666 	      }
5667 	
5668 	      /* free expression iterator */
5669 	      SCIPfreeExpriter(&it);
5670 	   }
5671 	
5672 	   /* check whether the bound disjunction constraint handler is available */
5673 	   hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5674 	
5675 	   /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5676 	   for( i = 0; i < nsinglelocked; ++i )
5677 	   {
5678 	      /* only consider expressions that are still contained in the exprcands map */
5679 	      if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5680 	      {
5681 	         SCIP_CONS* newcons;
5682 	         SCIP_VAR* vars[2];
5683 	         SCIP_BOUNDTYPE boundtypes[2];
5684 	         SCIP_Real bounds[2];
5685 	         char name[SCIP_MAXSTRLEN];
5686 	         SCIP_VAR* var;
5687 	
5688 	         var = SCIPgetVarExprVar(singlelocked[i]);
5689 	         assert(var != NULL);
5690 	         SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5691 	            SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5692 	
5693 	         /* try to change the variable type to binary */
5694 	         if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5695 	         {
5696 	            assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5697 	            SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5698 	            ++(*nchgvartypes);
5699 	
5700 	            if( *infeasible )
5701 	            {
5702 	               SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5703 	               break;
5704 	            }
5705 	         }
5706 	         /* add bound disjunction constraint if bounds of the variable are finite */
5707 	         else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5708 	         {
5709 	            vars[0] = var;
5710 	            vars[1] = var;
5711 	            boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5712 	            boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5713 	            bounds[0] = SCIPvarGetUbGlobal(var);
5714 	            bounds[1] = SCIPvarGetLbGlobal(var);
5715 	
5716 	            SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5717 	
5718 	            /* create, add, and release bound disjunction constraint */
5719 	            (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5720 	            SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5721 	               TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5722 	            SCIP_CALL( SCIPaddCons(scip, newcons) );
5723 	            SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5724 	            ++(*naddconss);
5725 	         }
5726 	      }
5727 	   }
5728 	
5729 	   /* free memory */
5730 	   SCIPfreeBufferArray(scip, &singlelocked);
5731 	   SCIPhashmapFree(&exprcands);
5732 	
5733 	   return SCIP_OKAY;
5734 	}
5735 	
5736 	/** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5737 	static
5738 	SCIP_RETCODE presolveImplint(
5739 	   SCIP*                 scip,               /**< SCIP data structure */
5740 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
5741 	   SCIP_CONS**           conss,              /**< nonlinear constraints */
5742 	   int                   nconss,             /**< total number of nonlinear constraints */
5743 	   int*                  nchgvartypes,       /**< pointer to update the total number of changed variable types */
5744 	   SCIP_Bool*            infeasible          /**< pointer to store whether problem is infeasible */
5745 	   )
5746 	{
5747 	   int c;
5748 	
5749 	   assert(scip != NULL);
5750 	   assert(conshdlr != NULL);
5751 	   assert(conss != NULL || nconss == 0);
5752 	   assert(nchgvartypes != NULL);
5753 	   assert(infeasible != NULL);
5754 	
5755 	   *infeasible = FALSE;
5756 	
5757 	   /* nothing can be done if there are no binary and integer variables available */
5758 	   if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5759 	      return SCIP_OKAY;
5760 	
5761 	   /* no continuous var can be made implicit-integer if there are no continuous variables */
5762 	   if( SCIPgetNContVars(scip) == 0 )
5763 	      return SCIP_OKAY;
5764 	
5765 	   for( c = 0; c < nconss; ++c )
5766 	   {
5767 	      SCIP_CONSDATA* consdata;
5768 	      SCIP_EXPR** children;
5769 	      int nchildren;
5770 	      SCIP_Real* coefs;
5771 	      SCIP_EXPR* cand = NULL;
5772 	      SCIP_Real candcoef = 0.0;
5773 	      int i;
5774 	
5775 	      assert(conss != NULL && conss[c] != NULL);
5776 	
5777 	      consdata = SCIPconsGetData(conss[c]);
5778 	      assert(consdata != NULL);
5779 	
5780 	      /* the constraint must be an equality constraint */
5781 	      if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5782 	         continue;
5783 	
5784 	      /* the root expression needs to be a sum expression */
5785 	      if( !SCIPisExprSum(scip, consdata->expr) )
5786 	         continue;
5787 	
5788 	      children = SCIPexprGetChildren(consdata->expr);
5789 	      nchildren = SCIPexprGetNChildren(consdata->expr);
5790 	
5791 	      /* the sum expression must have at least two children
5792 	       * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5793 	       */
5794 	      if( nchildren <= 1 )
5795 	         continue;
5796 	
5797 	      coefs = SCIPgetCoefsExprSum(consdata->expr);
5798 	
5799 	      /* find first continuous variable and get value of its coefficient */
5800 	      for( i = 0; i < nchildren; ++i )
5801 	      {
5802 	         if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5803 	            continue;
5804 	
5805 	         candcoef = coefs[i];
5806 	         assert(candcoef != 0.0);
5807 	
5808 	         /* lhs/rhs - constant divided by candcoef must be integral
5809 	          * if not, break with cand == NULL, so give up
5810 	          */
5811 	         if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5812 	            cand = children[i];
5813 	
5814 	         break;
5815 	      }
5816 	
5817 	      /* no suitable continuous variable found */
5818 	      if( cand == NULL )
5819 	         continue;
5820 	
5821 	      /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5822 	      for( i = 0; i < nchildren; ++i )
5823 	      {
5824 	         if( children[i] == cand )
5825 	            continue;
5826 	
5827 	         /* child i must be integral */
5828 	         if( !SCIPexprIsIntegral(children[i]) )
5829 	         {
5830 	            cand = NULL;
5831 	            break;
5832 	         }
5833 	
5834 	         /* coefficient of child i must be integral if diving by candcoef */
5835 	         if( !SCIPisIntegral(scip, coefs[i] / candcoef) )  /*lint !e414*/
5836 	         {
5837 	            cand = NULL;
5838 	            break;
5839 	         }
5840 	      }
5841 	
5842 	      if( cand == NULL )
5843 	         continue;
5844 	
5845 	      SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5846 	         SCIPvarGetName(SCIPgetVarExprVar(cand)), SCIPconsGetName(conss[c]));
5847 	
5848 	      /* change variable type */
5849 	      SCIP_CALL( SCIPchgVarType(scip, SCIPgetVarExprVar(cand), SCIP_VARTYPE_IMPLINT, infeasible) );
5850 	
5851 	      if( *infeasible )
5852 	         return SCIP_OKAY;
5853 	
5854 	      /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5855 	      SCIPexprSetIntegrality(cand, TRUE);
5856 	   }
5857 	
5858 	   return SCIP_OKAY;
5859 	}
5860 	
5861 	/** creates auxiliary variable for a given expression
5862 	 *
5863 	 * @note for a variable expression it does nothing
5864 	 * @note this function can only be called in stage SCIP_STAGE_SOLVING
5865 	 */
5866 	static
5867 	SCIP_RETCODE createAuxVar(
5868 	   SCIP*                 scip,               /**< SCIP data structure */
5869 	   SCIP_EXPR*            expr                /**< expression */
5870 	   )
5871 	{
5872 	   SCIP_EXPR_OWNERDATA* ownerdata;
5873 	   SCIP_CONSHDLRDATA* conshdlrdata;
5874 	   SCIP_VARTYPE vartype;
5875 	   SCIP_INTERVAL activity;
5876 	   char name[SCIP_MAXSTRLEN];
5877 	
5878 	   assert(scip != NULL);
5879 	   assert(expr != NULL);
5880 	
5881 	   ownerdata = SCIPexprGetOwnerData(expr);
5882 	   assert(ownerdata != NULL);
5883 	   assert(ownerdata->nauxvaruses > 0);
5884 	
5885 	   /* if we already have auxvar, then do nothing */
5886 	   if( ownerdata->auxvar != NULL )
5887 	      return SCIP_OKAY;
5888 	
5889 	   /* if expression is a variable-expression, then do nothing */
5890 	   if( SCIPisExprVar(scip, expr) )
5891 	      return SCIP_OKAY;
5892 	
5893 	   if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
5894 	   {
5895 	      SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
5896 	      return SCIP_INVALIDCALL;
5897 	   }
5898 	
5899 	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
5900 	   assert(conshdlrdata != NULL);
5901 	   assert(conshdlrdata->auxvarid >= 0);
5902 	
5903 	   /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
5904 	    * but it usually indicates a missing simplify
5905 	    * if we find situations where we need to have an auxvar for a constant, then remove this assert
5906 	    */
5907 	   assert(!SCIPisExprValue(scip, expr));
5908 	
5909 	   /* create and capture auxiliary variable */
5910 	   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
5911 	   ++conshdlrdata->auxvarid;
5912 	
5913 	   /* type of auxiliary variable depends on integrality information of the expression */
5914 	   vartype = SCIPexprIsIntegral(expr) ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS;
5915 	
5916 	   /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
5917 	   if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
5918 	   {
5919 	      activity = SCIPexprGetActivity(expr);
5920 	      /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
5921 	       * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
5922 	       * and abort in debug mode only
5923 	       */
5924 	      if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity) )
5925 	      {
5926 	         SCIPABORT();
5927 	         SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
5928 	      }
5929 	   }
5930 	   else
5931 	      SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &activity);
5932 	
5933 	   /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
5934 	    * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
5935 	    */
5936 	   if( SCIPgetDepth(scip) == 0 )
5937 	   {
5938 	      SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
5939 	   }
5940 	   else
5941 	   {
5942 	      SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
5943 	   }
5944 	
5945 	   /* mark the auxiliary variable to be added for the relaxation only
5946 	    * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
5947 	    * or to copy the variable to a subscip
5948 	    */
5949 	   SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
5950 	
5951 	   SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
5952 	
5953 	   SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
5954 	
5955 	   /* add variable locks in both directions
5956 	    * TODO should be sufficient to lock only according to expr->nlockspos/neg,
5957 	    *   but then we need to also update the auxvars locks when the expr locks change
5958 	    */
5959 	   SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
5960 	
5961 	#ifdef WITH_DEBUG_SOLUTION
5962 	   if( SCIPdebugIsMainscip(scip) )
5963 	   {
5964 	      /* store debug solution value of auxiliary variable
5965 	       * assumes that expression has been evaluated in debug solution before
5966 	       */
5967 	      SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
5968 	   }
5969 	#endif
5970 	
5971 	   if( SCIPgetDepth(scip) > 0 )
5972 	   {
5973 	      /* initialize local bounds to (locally valid) activity */
5974 	      SCIP_Bool cutoff;
5975 	      SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
5976 	      assert(!cutoff);  /* should not happen as activity wasn't empty and variable is new */
5977 	   }
5978 	
5979 	   return SCIP_OKAY;
5980 	}
5981 	
5982 	/** initializes separation for constraint
5983 	 *
5984 	 * - ensures that activities are up to date in all expressions
5985 	 * - creates auxiliary variables where required
5986 	 * - calls propExprDomains() to possibly tighten auxvar bounds
5987 	 * - calls separation initialization callback of nlhdlrs
5988 	 */
5989 	static
5990 	SCIP_RETCODE initSepa(
5991 	   SCIP*                 scip,               /**< SCIP data structure */
5992 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
5993 	   SCIP_CONS**           conss,              /**< constraints */
5994 	   int                   nconss,             /**< number of constraints */
5995 	   SCIP_Bool*            infeasible          /**< pointer to store whether the problem is infeasible or not */
5996 	   )
5997 	{
5998 	   SCIP_CONSDATA* consdata;
5999 	   SCIP_CONSHDLRDATA* conshdlrdata;
6000 	   SCIP_EXPRITER* it;
6001 	   SCIP_EXPR* expr;
6002 	   SCIP_RESULT result;
6003 	   SCIP_VAR* auxvar;
6004 	   int nreductions = 0;
6005 	   int c, e;
6006 	
6007 	   assert(scip != NULL);
6008 	   assert(conshdlr != NULL);
6009 	   assert(conss != NULL || nconss == 0);
6010 	   assert(nconss >= 0);
6011 	   assert(infeasible != NULL);
6012 	
6013 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6014 	   assert(conshdlrdata != NULL);
6015 	
6016 	   /* start with new propbounds (just to be sure, should not be needed) */
6017 	   ++conshdlrdata->curpropboundstag;
6018 	
6019 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6020 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6021 	
6022 	   /* first ensure activities are up to date and create auxvars */
6023 	   *infeasible = FALSE;
6024 	   for( c = 0; c < nconss; ++c )
6025 	   {
6026 	      assert(conss != NULL);
6027 	      assert(conss[c] != NULL);
6028 	
6029 	      consdata = SCIPconsGetData(conss[c]);
6030 	      assert(consdata != NULL);
6031 	      assert(consdata->expr != NULL);
6032 	
6033 	#ifdef WITH_DEBUG_SOLUTION
6034 	      if( SCIPdebugIsMainscip(scip) )
6035 	      {
6036 	         SCIP_SOL* debugsol;
6037 	
6038 	         SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6039 	
6040 	         if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6041 	         {
6042 	            /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6043 	             * in createAuxVar()
6044 	             */
6045 	            SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6046 	         }
6047 	      }
6048 	#endif
6049 	
6050 	      /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6051 	      SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6052 	
6053 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6054 	      {
6055 	         if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6056 	         {
6057 	            SCIP_CALL( createAuxVar(scip, expr) );
6058 	         }
6059 	      }
6060 	
6061 	      auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6062 	      if( auxvar != NULL )
6063 	      {
6064 	         SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6065 	               SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6066 	         /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6067 	         SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6068 	         if( *infeasible )
6069 	         {
6070 	            SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6071 	            break;
6072 	         }
6073 	
6074 	         SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6075 	         if( *infeasible )
6076 	         {
6077 	            SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6078 	            break;
6079 	         }
6080 	      }
6081 	   }
6082 	
6083 	   /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6084 	    * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6085 	    * (e.g., log(x*y), which becomes log(w), w=x*y
6086 	    *  log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6087 	    */
6088 	   SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6089 	   if( result == SCIP_CUTOFF )
6090 	      *infeasible = TRUE;
6091 	
6092 	   /* now call initsepa of nlhdlrs
6093 	    * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6094 	    *   but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6095 	    */
6096 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6097 	   for( c = 0; c < nconss && !*infeasible; ++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 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6107 	      {
6108 	         SCIP_EXPR_OWNERDATA* ownerdata;
6109 	
6110 	         ownerdata = SCIPexprGetOwnerData(expr);
6111 	         assert(ownerdata != NULL);
6112 	
6113 	         if( ownerdata->nauxvaruses == 0 )
6114 	            continue;
6115 	
6116 	         for( e = 0; e < ownerdata->nenfos; ++e )
6117 	         {
6118 	            SCIP_NLHDLR* nlhdlr;
6119 	            SCIP_Bool underestimate;
6120 	            SCIP_Bool overestimate;
6121 	            assert(ownerdata->enfos[e] != NULL);
6122 	
6123 	            /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6124 	             * which participated in a previous initSepa() call
6125 	             */
6126 	            if( ownerdata->enfos[e]->issepainit )
6127 	               continue;
6128 	
6129 	            /* only call initsepa if it will actually separate */
6130 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6131 	               continue;
6132 	
6133 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
6134 	            assert(nlhdlr != NULL);
6135 	
6136 	            /* only init sepa if there is an initsepa callback */
6137 	            if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6138 	               continue;
6139 	
6140 	            /* check whether expression needs to be under- or overestimated */
6141 	            overestimate = ownerdata->nlocksneg > 0;
6142 	            underestimate = ownerdata->nlockspos > 0;
6143 	            assert(underestimate || overestimate);
6144 	
6145 	            SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6146 	
6147 	            /* call the separation initialization callback of the nonlinear handler */
6148 	            SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6149 	               ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6150 	            ownerdata->enfos[e]->issepainit = TRUE;
6151 	
6152 	            if( *infeasible )
6153 	            {
6154 	               /* stop everything if we detected infeasibility */
6155 	               SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6156 	               break;
6157 	            }
6158 	         }
6159 	      }
6160 	   }
6161 	
6162 	   SCIPfreeExpriter(&it);
6163 	
6164 	   return SCIP_OKAY;
6165 	}
6166 	
6167 	/** returns whether we are ok to branch on auxiliary variables
6168 	 *
6169 	 * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6170 	 */
6171 	static
6172 	SCIP_Bool branchAuxNonlinear(
6173 	   SCIP*                 scip,               /**< SCIP data structure */
6174 	   SCIP_CONSHDLR*        conshdlr            /**< constraint handler */
6175 	   )
6176 	{
6177 	   SCIP_CONSHDLRDATA* conshdlrdata;
6178 	
6179 	   assert(conshdlr != NULL);
6180 	
6181 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6182 	   assert(conshdlrdata != NULL);
6183 	
6184 	   return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6185 	}
6186 	
6187 	/** gets weight of variable when splitting violation score onto several variables in an expression */
6188 	static
6189 	SCIP_Real getViolSplitWeight(
6190 	   SCIP*                 scip,               /**< SCIP data structure */
6191 	   SCIP_CONSHDLR*        conshdlr,           /**< expr constraint handler */
6192 	   SCIP_VAR*             var,                /**< variable */
6193 	   SCIP_SOL*             sol                 /**< current solution */
6194 	   )
6195 	{
6196 	   SCIP_CONSHDLRDATA* conshdlrdata;
6197 	
6198 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6199 	   assert(conshdlrdata != NULL);
6200 	
6201 	   switch( conshdlrdata->branchviolsplit )
6202 	   {
6203 	      case 'u' :  /* uniform: everyone gets the same score */
6204 	         return 1.0;
6205 	
6206 	      case 'm' :  /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6207 	      {
6208 	         SCIP_Real weight;
6209 	         weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6210 	         return MAX(0.05, weight);
6211 	      }
6212 	
6213 	      case 'd' :  /* domain width */
6214 	         return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6215 	
6216 	      case 'l' :  /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6217 	      {
6218 	         SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6219 	         assert(width > 0.0);
6220 	         if( width > 10.0 )
6221 	            return 10.0*log10(width);
6222 	         if( width < 0.1 )
6223 	            return 0.1/(-log10(width));
6224 	         return width;
6225 	      }
6226 	
6227 	      default :
6228 	         SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6229 	         SCIPABORT();
6230 	         return SCIP_INVALID;
6231 	   }
6232 	}
6233 	
6234 	/** adds violation-branching score to a set of expressions, thereby distributing the score
6235 	 *
6236 	 * Each expression must either be a variable expression or have an aux-variable.
6237 	 *
6238 	 * If unbounded variables are present, each unbounded var gets an even score.
6239 	 * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6240 	 */
6241 	static
6242 	void addExprsViolScore(
6243 	   SCIP*                 scip,               /**< SCIP data structure */
6244 	   SCIP_EXPR**           exprs,              /**< expressions where to add branching score */
6245 	   int                   nexprs,             /**< number of expressions */
6246 	   SCIP_Real             violscore,          /**< violation-branching score to add to expression */
6247 	   SCIP_SOL*             sol,                /**< current solution */
6248 	   SCIP_Bool*            success             /**< buffer to store whether at least one violscore was added */
6249 	   )
6250 	{
6251 	   SCIP_CONSHDLR* conshdlr;
6252 	   SCIP_VAR* var;
6253 	   SCIP_Real weight;
6254 	   SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6255 	   int nunbounded = 0;  /* number of candidates with unbounded domain */
6256 	   int i;
6257 	
6258 	   assert(exprs != NULL);
6259 	   assert(nexprs > 0);
6260 	   assert(success != NULL);
6261 	
6262 	   if( nexprs == 1 )
6263 	   {
6264 	      SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6265 	      SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6266 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(exprs[0])), SCIPvarGetLbLocal(SCIPgetExprAuxVarNonlinear(exprs[0])), SCIPvarGetUbLocal(SCIPgetExprAuxVarNonlinear(exprs[0])));
6267 	      *success = TRUE;
6268 	      return;
6269 	   }
6270 	
6271 	   conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6272 	
6273 	   for( i = 0; i < nexprs; ++i )
6274 	   {
6275 	      var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6276 	      assert(var != NULL);
6277 	
6278 	      if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6279 	         ++nunbounded;
6280 	      else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6281 	         weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6282 	   }
6283 	
6284 	   *success = FALSE;
6285 	   for( i = 0; i < nexprs; ++i )
6286 	   {
6287 	      var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6288 	      assert(var != NULL);
6289 	
6290 	      if( nunbounded > 0 )
6291 	      {
6292 	         if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6293 	         {
6294 	            SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6295 	            SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6296 	               100.0/nunbounded, violscore,
6297 	               SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6298 	            *success = TRUE;
6299 	         }
6300 	      }
6301 	      else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6302 	      {
6303 	         assert(weightsum > 0.0);
6304 	
6305 	         weight = getViolSplitWeight(scip, conshdlr, var, sol);
6306 	         SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6307 	         SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6308 	            100*weight / weightsum, violscore,
6309 	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6310 	         *success = TRUE;
6311 	      }
6312 	      else
6313 	      {
6314 	         SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6315 	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6316 	      }
6317 	   }
6318 	}
6319 	
6320 	/** adds violation-branching score to children of expression for given auxiliary variables
6321 	 *
6322 	 * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6323 	 * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6324 	 *
6325 	 * @note This method may modify the given auxvars array by means of sorting.
6326 	 */
6327 	static
6328 	SCIP_RETCODE addExprViolScoresAuxVars(
6329 	   SCIP*                 scip,               /**< SCIP data structure */
6330 	   SCIP_EXPR*            expr,               /**< expression where to start searching */
6331 	   SCIP_Real             violscore,          /**< violation score to add to expression */
6332 	   SCIP_VAR**            auxvars,            /**< auxiliary variables for which to find expression */
6333 	   int                   nauxvars,           /**< number of auxiliary variables */
6334 	   SCIP_SOL*             sol,                /**< current solution (NULL for the LP solution) */
6335 	   SCIP_Bool*            success             /**< buffer to store whether at least one violscore was added */
6336 	   )
6337 	{
6338 	   SCIP_EXPRITER* it;
6339 	   SCIP_VAR* auxvar;
6340 	   SCIP_EXPR** exprs;
6341 	   int nexprs;
6342 	   int pos;
6343 	
6344 	   assert(scip != NULL);
6345 	   assert(expr != NULL);
6346 	   assert(auxvars != NULL);
6347 	   assert(success != NULL);
6348 	
6349 	   /* sort variables to make lookup below faster */
6350 	   SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6351 	
6352 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6353 	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_BFS, FALSE) );
6354 	
6355 	   SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6356 	   nexprs = 0;
6357 	
6358 	   for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6359 	   {
6360 	      auxvar = SCIPgetExprAuxVarNonlinear(expr);
6361 	      if( auxvar == NULL )
6362 	         continue;
6363 	
6364 	      /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6365 	      if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6366 	      {
6367 	         assert(auxvars[pos] == auxvar);
6368 	
6369 	         SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6370 	         exprs[nexprs++] = expr;
6371 	
6372 	         if( nexprs == nauxvars )
6373 	            break;
6374 	      }
6375 	   }
6376 	
6377 	   SCIPfreeExpriter(&it);
6378 	
6379 	   if( nexprs > 0 )
6380 	   {
6381 	      SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6382 	   }
6383 	   else
6384 	      *success = FALSE;
6385 	
6386 	   SCIPfreeBufferArray(scip, &exprs);
6387 	
6388 	   return SCIP_OKAY;
6389 	}
6390 	
6391 	/** registers all unfixed variables in violated constraints as branching candidates */
6392 	static
6393 	SCIP_RETCODE registerBranchingCandidatesAllUnfixed(
6394 	   SCIP*                 scip,               /**< SCIP data structure */
6395 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6396 	   SCIP_CONS**           conss,              /**< constraints */
6397 	   int                   nconss,             /**< number of constraints */
6398 	   int*                  nnotify             /**< counter for number of notifications performed */
6399 	   )
6400 	{
6401 	   SCIP_CONSDATA* consdata;
6402 	   SCIP_VAR* var;
6403 	   int c;
6404 	   int i;
6405 	
6406 	   assert(conshdlr != NULL);
6407 	   assert(conss != NULL || nconss == 0);
6408 	   assert(nnotify != NULL);
6409 	
6410 	   *nnotify = 0;
6411 	
6412 	   for( c = 0; c < nconss; ++c )
6413 	   {
6414 	      assert(conss != NULL && conss[c] != NULL);
6415 	
6416 	      consdata = SCIPconsGetData(conss[c]);
6417 	      assert(consdata != NULL);
6418 	
6419 	      /* consider only violated constraints */
6420 	      if( !isConsViolated(scip, conss[c]) )
6421 	         continue;
6422 	
6423 	      /* register all variables that have not been fixed yet */
6424 	      assert(consdata->varexprs != NULL);
6425 	      for( i = 0; i < consdata->nvarexprs; ++i )
6426 	      {
6427 	         var = SCIPgetVarExprVar(consdata->varexprs[i]);
6428 	         assert(var != NULL);
6429 	
6430 	         if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6431 	         {
6432 	            SCIP_CALL( SCIPaddExternBranchCand(scip, var, getConsAbsViolation(conss[c]), SCIP_INVALID) );
6433 	            ++(*nnotify);
6434 	         }
6435 	      }
6436 	   }
6437 	
6438 	   return SCIP_OKAY;
6439 	}
6440 	
6441 	/** registers all variables in violated constraints with branching scores as external branching candidates */
6442 	static
6443 	SCIP_RETCODE registerBranchingCandidates(
6444 	   SCIP*                 scip,               /**< SCIP data structure */
6445 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6446 	   SCIP_CONS**           conss,              /**< constraints */
6447 	   int                   nconss,             /**< number of constraints */
6448 	   SCIP_Bool*            success             /**< buffer to store whether at least one branching candidate was added */
6449 	   )
6450 	{
6451 	   SCIP_CONSDATA* consdata;
6452 	   SCIP_EXPRITER* it = NULL;
6453 	   int c;
6454 	
6455 	   assert(conshdlr != NULL);
6456 	   assert(success != NULL);
6457 	
6458 	   *success = FALSE;
6459 	
6460 	   if( branchAuxNonlinear(scip, conshdlr) )
6461 	   {
6462 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6463 	      SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6464 	   }
6465 	
6466 	   /* register external branching candidates */
6467 	   for( c = 0; c < nconss; ++c )
6468 	   {
6469 	      assert(conss != NULL && conss[c] != NULL);
6470 	
6471 	      consdata = SCIPconsGetData(conss[c]);
6472 	      assert(consdata != NULL);
6473 	      assert(consdata->varexprs != NULL);
6474 	
6475 	      /* consider only violated constraints */
6476 	      if( !isConsViolated(scip, conss[c]) )
6477 	         continue;
6478 	
6479 	      if( !branchAuxNonlinear(scip, conshdlr) )
6480 	      {
6481 	         int i;
6482 	
6483 	         /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6484 	          * only, so we can loop over variable expressions
6485 	          */
6486 	         for( i = 0; i < consdata->nvarexprs; ++i )
6487 	         {
6488 	            SCIP_Real violscore;
6489 	            SCIP_Real lb;
6490 	            SCIP_Real ub;
6491 	            SCIP_VAR* var;
6492 	
6493 	            violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6494 	
6495 	            /* skip variable expressions that do not have a violation score */
6496 	            if( violscore == 0.0 )
6497 	               continue;
6498 	
6499 	            var = SCIPgetVarExprVar(consdata->varexprs[i]);
6500 	            assert(var != NULL);
6501 	
6502 	            lb = SCIPvarGetLbLocal(var);
6503 	            ub = SCIPvarGetUbLocal(var);
6504 	
6505 	            /* consider variable for branching if it has not been fixed yet */
6506 	            if( !SCIPisEQ(scip, lb, ub) )
6507 	            {
6508 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6509 	               SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6510 	               *success = TRUE;
6511 	            }
6512 	            else
6513 	            {
6514 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6515 	            }
6516 	
6517 	            /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6518 	             * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6519 	             */
6520 	            SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6521 	         }
6522 	      }
6523 	      else
6524 	      {
6525 	         SCIP_EXPR* expr;
6526 	         SCIP_VAR* var;
6527 	         SCIP_Real lb;
6528 	         SCIP_Real ub;
6529 	         SCIP_Real violscore;
6530 	
6531 	         for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6532 	         {
6533 	            violscore = SCIPgetExprViolScoreNonlinear(expr);
6534 	            if( violscore == 0.0 )
6535 	               continue;
6536 	
6537 	            /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6538 	             * variable, so this expression should either be an original variable or have an auxiliary variable
6539 	             */
6540 	            var = SCIPgetExprAuxVarNonlinear(expr);
6541 	            assert(var != NULL);
6542 	
6543 	            lb = SCIPvarGetLbLocal(var);
6544 	            ub = SCIPvarGetUbLocal(var);
6545 	
6546 	            /* consider variable for branching if it has not been fixed yet */
6547 	            if( !SCIPisEQ(scip, lb, ub) )
6548 	            {
6549 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6550 	
6551 	               SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6552 	               *success = TRUE;
6553 	            }
6554 	            else
6555 	            {
6556 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6557 	            }
6558 	         }
6559 	      }
6560 	   }
6561 	
6562 	   if( it != NULL )
6563 	      SCIPfreeExpriter(&it);
6564 	
6565 	   return SCIP_OKAY;
6566 	}
6567 	
6568 	/** collect branching candidates from violated constraints
6569 	 *
6570 	 * Fills array with expressions that serve as branching candidates.
6571 	 * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6572 	 * branching candidate.
6573 	 *
6574 	 * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6575 	 * through variable-expressions only.
6576 	 */
6577 	static
6578 	SCIP_RETCODE collectBranchingCandidates(
6579 	   SCIP*                 scip,               /**< SCIP data structure */
6580 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6581 	   SCIP_CONS**           conss,              /**< constraints to process */
6582 	   int                   nconss,             /**< number of constraints */
6583 	   SCIP_Real             maxrelconsviol,     /**< maximal scaled constraint violation */
6584 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
6585 	   SCIP_Longint          soltag,             /**< tag of solution */
6586 	   BRANCHCAND*           cands,              /**< array where to store candidates, must be at least SCIPgetNVars() long */
6587 	   int*                  ncands              /**< number of candidates found */
6588 	   )
6589 	{
6590 	   SCIP_CONSHDLRDATA* conshdlrdata;
6591 	   SCIP_CONSDATA* consdata;
6592 	   SCIP_EXPRITER* it = NULL;
6593 	   int c;
6594 	   int attempt;
6595 	   SCIP_VAR* var;
6596 	
6597 	   assert(scip != NULL);
6598 	   assert(conshdlr != NULL);
6599 	   assert(cands != NULL);
6600 	   assert(ncands != NULL);
6601 	
6602 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6603 	   assert(conshdlrdata != NULL);
6604 	
6605 	   if( branchAuxNonlinear(scip, conshdlr) )
6606 	   {
6607 	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6608 	      SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
6609 	   }
6610 	
6611 	   *ncands = 0;
6612 	   for( attempt = 0; attempt < 2; ++attempt )
6613 	   {
6614 	      /* collect branching candidates from violated constraints
6615 	       * in the first attempt, consider only constraints with large violation
6616 	       * in the second attempt, consider all remaining violated constraints
6617 	       */
6618 	      for( c = 0; c < nconss; ++c )
6619 	      {
6620 	         SCIP_Real consviol;
6621 	
6622 	         assert(conss != NULL && conss[c] != NULL);
6623 	
6624 	         /* consider only violated constraints */
6625 	         if( !isConsViolated(scip, conss[c]) )
6626 	            continue;
6627 	
6628 	         consdata = SCIPconsGetData(conss[c]);
6629 	         assert(consdata != NULL);
6630 	         assert(consdata->varexprs != NULL);
6631 	
6632 	         SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6633 	
6634 	         if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6635 	            continue;
6636 	         else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6637 	            continue;
6638 	
6639 	         if( !branchAuxNonlinear(scip, conshdlr) )
6640 	         {
6641 	            int i;
6642 	
6643 	            /* if not branching on auxvars, then violation-branching scores will be available for original variables
6644 	             * only, so we can loop over variable expressions
6645 	             * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6646 	             * variable, therefore we invalidate the score of a variable after processing it.
6647 	             */
6648 	            for( i = 0; i < consdata->nvarexprs; ++i )
6649 	            {
6650 	               SCIP_Real lb;
6651 	               SCIP_Real ub;
6652 	
6653 	               /* skip variable expressions that do not have a valid violation score */
6654 	               if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6655 	                  continue;
6656 	
6657 	               var = SCIPgetVarExprVar(consdata->varexprs[i]);
6658 	               assert(var != NULL);
6659 	
6660 	               lb = SCIPvarGetLbLocal(var);
6661 	               ub = SCIPvarGetUbLocal(var);
6662 	
6663 	               /* skip already fixed variable */
6664 	               if( SCIPisEQ(scip, lb, ub) )
6665 	               {
6666 	                  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6667 	                  continue;
6668 	               }
6669 	
6670 	               assert(*ncands + 1 < SCIPgetNVars(scip));
6671 	               cands[*ncands].expr = consdata->varexprs[i];
6672 	               cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6673 	               ++(*ncands);
6674 	
6675 	               /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6676 	                * several times as external branching candidate */
6677 	               SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6678 	            }
6679 	         }
6680 	         else
6681 	         {
6682 	            SCIP_EXPR* expr;
6683 	            SCIP_Real lb;
6684 	            SCIP_Real ub;
6685 	
6686 	            for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6687 	            {
6688 	               if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6689 	                  continue;
6690 	
6691 	               /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6692 	                * variables, so this expression should either be an original variable or have an auxiliary variable
6693 	                */
6694 	               var = SCIPgetExprAuxVarNonlinear(expr);
6695 	               assert(var != NULL);
6696 	
6697 	               lb = SCIPvarGetLbLocal(var);
6698 	               ub = SCIPvarGetUbLocal(var);
6699 	
6700 	               /* skip already fixed variable */
6701 	               if( SCIPisEQ(scip, lb, ub) )
6702 	               {
6703 	                  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6704 	                  continue;
6705 	               }
6706 	
6707 	               assert(*ncands + 1 < SCIPgetNVars(scip));
6708 	               cands[*ncands].expr = expr;
6709 	               cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6710 	               ++(*ncands);
6711 	            }
6712 	         }
6713 	      }
6714 	
6715 	      /* if we have branching candidates, then we don't need another attempt */
6716 	      if( *ncands > 0 )
6717 	         break;
6718 	   }
6719 	
6720 	   if( it != NULL )
6721 	      SCIPfreeExpriter(&it);
6722 	
6723 	   return SCIP_OKAY;
6724 	}
6725 	
6726 	/** computes a branching score for a variable that reflects how important branching on this variable would be for
6727 	 * improving the dual bound from the LP relaxation
6728 	 *
6729 	 * Assume the Lagrangian for the current LP is something of the form
6730 	 *   L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6731 	 * where x are the original variables, z the auxiliary variables,
6732 	 * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6733 	 *
6734 	 * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6735 	 * If we could have used not only an estimator, but the actual function f(x), then this would
6736 	 * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6737 	 * Using a lot of handwaving, we claim that
6738 	 *   lambda_i * (f(x) - a_i'x + b_i)
6739 	 * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6740 	 * If an estimator depended on local bounds, then it could be improved by branching.
6741 	 * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6742 	 *
6743 	 * 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.
6744 	 * To scale, we divide by the LP objective value (if >1).
6745 	 *
6746 	 * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6747 	 *     these are affected by the bounds on original variables indirectly (through forward-propagation)
6748 	 *
6749 	 * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6750 	 *     in effect, we should go from the row to the expression for which it was generated and consider only variables that
6751 	 *     would also be branching candidates
6752 	 */
6753 	static
6754 	SCIP_Real getDualBranchscore(
6755 	   SCIP*                 scip,               /**< SCIP data structure */
6756 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
6757 	   SCIP_VAR*             var                 /**< variable */
6758 	   )
6759 	{
6760 	   SCIP_COL* col;
6761 	   SCIP_ROW** rows;
6762 	   int nrows;
6763 	   int r;
6764 	   SCIP_Real dualscore;
6765 	
6766 	   assert(scip != NULL);
6767 	   assert(conshdlr != NULL);
6768 	   assert(var != NULL);
6769 	
6770 	   /* if LP not solved, then the dual branching score is not available */
6771 	   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
6772 	      return 0.0;
6773 	
6774 	   /* if var is not in the LP, then the dual branching score is not available */
6775 	   if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_COLUMN )
6776 	      return 0.0;
6777 	
6778 	   col = SCIPvarGetCol(var);
6779 	   assert(col != NULL);
6780 	
6781 	   if( !SCIPcolIsInLP(col) )
6782 	      return 0.0;
6783 	
6784 	   nrows = SCIPcolGetNLPNonz(col);  /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6785 	   rows = SCIPcolGetRows(col);
6786 	
6787 	   /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6788 	
6789 	   /* aggregate duals from all rows from consexpr with non-zero dual
6790 	    * TODO: this is a quick-and-dirty implementation, and not used by default
6791 	    *   in the long run, this should be either removed or replaced by a proper implementation
6792 	    */
6793 	   dualscore = 0.0;
6794 	   for( r = 0; r < nrows; ++r )
6795 	   {
6796 	      SCIP_Real estimategap;
6797 	      const char* estimategapstr;
6798 	
6799 	      /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6800 	       * these would typically be local, unless they are created at the root node
6801 	       * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6802 	      if( !SCIProwIsLocal(rows[r]) )
6803 	         continue;
6804 	       */
6805 	      if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6806 	         continue;
6807 	      if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6808 	         continue;
6809 	
6810 	      estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6811 	      if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6812 	         continue;
6813 	      estimategap = atof(estimategapstr + 13);
6814 	      assert(estimategap >= 0.0);
6815 	      if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6816 	         estimategap = SCIPgetHugeValue(scip);
6817 	
6818 	      /* SCIPinfoMessage(scip, enfologfile, "  row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6819 	      SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6820 	
6821 	      dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6822 	   }
6823 	
6824 	   /* divide by optimal value of LP for scaling */
6825 	   dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6826 	
6827 	   return dualscore;
6828 	}
6829 	
6830 	/** computes branching scores (including weighted score) for a set of candidates
6831 	 *
6832 	 * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6833 	 * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6834 	 *
6835 	 * For each score, compute the maximum over all candidates.
6836 	 *
6837 	 * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6838 	 * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6839 	 * score of all candidates.
6840 	 * Further divide by the sum of all weights where a score was available (even if the score was 0).
6841 	 *
6842 	 * For example:
6843 	 * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6844 	 * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6845 	 * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6846 	 * - 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.
6847 	 *   The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6848 	 */
6849 	static
6850 	void scoreBranchingCandidates(
6851 	   SCIP*                 scip,               /**< SCIP data structure */
6852 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6853 	   BRANCHCAND*           cands,              /**< branching candidates */
6854 	   int                   ncands,             /**< number of candidates */
6855 	   SCIP_SOL*             sol                 /**< solution to enforce (NULL for the LP solution) */
6856 	   )
6857 	{
6858 	   SCIP_CONSHDLRDATA* conshdlrdata;
6859 	   BRANCHCAND maxscore;
6860 	   int c;
6861 	
6862 	   assert(scip != NULL);
6863 	   assert(conshdlr != NULL);
6864 	   assert(cands != NULL);
6865 	   assert(ncands > 0);
6866 	
6867 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
6868 	   assert(conshdlrdata != NULL);
6869 	
6870 	   /* initialize counts to 0 */
6871 	   memset(&maxscore, 0, sizeof(BRANCHCAND));
6872 	
6873 	   for( c = 0; c < ncands; ++c )
6874 	   {
6875 	      if( conshdlrdata->branchviolweight > 0.0 )
6876 	      {
6877 	         /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6878 	         maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6879 	      }
6880 	
6881 	      if( conshdlrdata->branchdomainweight > 0.0 )
6882 	      {
6883 	         SCIP_Real domainwidth;
6884 	         SCIP_VAR* var;
6885 	
6886 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6887 	         assert(var != NULL);
6888 	
6889 	         /* get domain width, taking infinity at 1e20 on purpose */
6890 	         domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6891 	
6892 	         /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6893 	          * and log(2 * infinity *  MAX(epsilon, domainwidth)) for domain width < 1
6894 	          * the idea is to penalize very large and very small domains
6895 	          */
6896 	         if( domainwidth >= 1.0 )
6897 	            cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
6898 	         else
6899 	            cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
6900 	
6901 	         maxscore.domain = MAX(cands[c].domain, maxscore.domain);
6902 	      }
6903 	      else
6904 	         cands[c].domain = 0.0;
6905 	
6906 	      if( conshdlrdata->branchdualweight > 0.0 )
6907 	      {
6908 	         SCIP_VAR* var;
6909 	
6910 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6911 	         assert(var != NULL);
6912 	
6913 	         cands[c].dual = getDualBranchscore(scip, conshdlr, var);
6914 	         maxscore.dual = MAX(cands[c].dual, maxscore.dual);
6915 	      }
6916 	
6917 	      if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
6918 	      {
6919 	         SCIP_VAR* var;
6920 	
6921 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6922 	         assert(var != NULL);
6923 	
6924 	         if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6925 	            cands[c].pscost = SCIP_INVALID;
6926 	         else
6927 	         {
6928 	            SCIP_Real brpoint;
6929 	            SCIP_Real pscostdown;
6930 	            SCIP_Real pscostup;
6931 	            char strategy;
6932 	
6933 	            /* decide how to compute pseudo-cost scores
6934 	             * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
6935 	             * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
6936 	             */
6937 	            if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
6938 	               strategy = conshdlrdata->branchpscostupdatestrategy;
6939 	            else
6940 	               strategy = 'l';
6941 	
6942 	            brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
6943 	
6944 	            /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
6945 	             * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
6946 	             * For here, I use a simple #counts >= branchpscostreliable.
6947 	             * TODO use SCIPgetVarPseudocostCount() instead?
6948 	             */
6949 	            if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
6950 	            {
6951 	               switch( strategy )
6952 	               {
6953 	                  case 's' :
6954 	                     pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
6955 	                     break;
6956 	                  case 'd' :
6957 	                     pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
6958 	                     break;
6959 	                  case 'l' :
6960 	                     if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
6961 	                        pscostdown = SCIP_INVALID;
6962 	                     else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
6963 	                        pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
6964 	                     else
6965 	                        pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, NULL, var) - SCIPadjustedVarUb(scip, var, brpoint)));
6966 	                     break;
6967 	                  default :
6968 	                     SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
6969 	                     pscostdown = SCIP_INVALID;
6970 	               }
6971 	            }
6972 	            else
6973 	               pscostdown = SCIP_INVALID;
6974 	
6975 	            if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
6976 	            {
6977 	               switch( strategy )
6978 	               {
6979 	                  case 's' :
6980 	                     pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
6981 	                     break;
6982 	                  case 'd' :
6983 	                     pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
6984 	                     break;
6985 	                  case 'l' :
6986 	                     if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
6987 	                        pscostup = SCIP_INVALID;
6988 	                     else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
6989 	                        pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
6990 	                     else
6991 	                        pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, NULL, var) );
6992 	                     break;
6993 	                  default :
6994 	                     SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
6995 	                     pscostup = SCIP_INVALID;
6996 	               }
6997 	            }
6998 	            else
6999 	               pscostup = SCIP_INVALID;
7000 	
7001 	            /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7002 	             * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7003 	             */
7004 	            if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7005 	               cands[c].pscost = SCIP_INVALID;
7006 	            else if( pscostdown == SCIP_INVALID )
7007 	               cands[c].pscost = pscostup;
7008 	            else if( pscostup == SCIP_INVALID )
7009 	               cands[c].pscost = pscostdown;
7010 	            else
7011 	               cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup);  /* pass NULL for var to avoid multiplication with branch-factor */
7012 	         }
7013 	
7014 	         if( cands[c].pscost != SCIP_INVALID )
7015 	            maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7016 	      }
7017 	
7018 	      if( conshdlrdata->branchvartypeweight > 0.0 )
7019 	      {
7020 	         SCIP_VAR* var;
7021 	
7022 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7023 	         assert(var != NULL);
7024 	
7025 	         switch( SCIPvarGetType(var) )
7026 	         {
7027 	            case SCIP_VARTYPE_BINARY :
7028 	               cands[c].vartype = 1.0;
7029 	               break;
7030 	            case SCIP_VARTYPE_INTEGER :
7031 	               cands[c].vartype = 0.1;
7032 	               break;
7033 	            case SCIP_VARTYPE_IMPLINT :
7034 	               cands[c].vartype = 0.01;
7035 	               break;
7036 	            case SCIP_VARTYPE_CONTINUOUS :
7037 	            default:
7038 	               cands[c].vartype = 0.0;
7039 	         }
7040 	         maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7041 	      }
7042 	   }
7043 	
7044 	   /* now compute a weighted score for each candidate from the single scores
7045 	    * the single scores are scaled to be in [0,1] for this
7046 	    */
7047 	   for( c = 0; c < ncands; ++c )
7048 	   {
7049 	      SCIP_Real weightsum;
7050 	
7051 	      ENFOLOG(
7052 	         SCIP_VAR* var;
7053 	         var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7054 	         SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7055 	         )
7056 	
7057 	      cands[c].weighted = 0.0;
7058 	      weightsum = 0.0;
7059 	
7060 	      if( maxscore.auxviol > 0.0 )
7061 	      {
7062 	         cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7063 	         weightsum += conshdlrdata->branchviolweight;
7064 	
7065 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7066 	      }
7067 	
7068 	      if( maxscore.domain > 0.0 )
7069 	      {
7070 	         cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7071 	         weightsum += conshdlrdata->branchdomainweight;
7072 	
7073 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7074 	      }
7075 	
7076 	      if( maxscore.dual > 0.0 )
7077 	      {
7078 	         cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7079 	         weightsum += conshdlrdata->branchdualweight;
7080 	
7081 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7082 	      }
7083 	
7084 	      if( maxscore.pscost > 0.0 )
7085 	      {
7086 	         /* use pseudo-costs only if available */
7087 	         if( cands[c].pscost != SCIP_INVALID )
7088 	         {
7089 	            cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7090 	            weightsum += conshdlrdata->branchpscostweight;
7091 	
7092 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7093 	         }
7094 	         else
7095 	         {
7096 	            /* do not add pscostscore, if not available, also do not add into weightsum */
7097 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0*    n/a(pscost)"); )
7098 	         }
7099 	      }
7100 	
7101 	      if( maxscore.vartype > 0.0 )
7102 	      {
7103 	         cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7104 	         weightsum += conshdlrdata->branchvartypeweight;
7105 	
7106 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7107 	      }
7108 	      assert(weightsum > 0.0);  /* we should have got at least one valid score */
7109 	      cands[c].weighted /= weightsum;
7110 	
7111 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7112 	   }
7113 	}
7114 	
7115 	/** compare two branching candidates by their weighted score
7116 	 *
7117 	 * if weighted score is equal, use variable index of (aux)var
7118 	 */
7119 	static
7120 	SCIP_DECL_SORTINDCOMP(branchcandCompare)
7121 	{
7122 	   BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7123 	
7124 	   if( cands[ind1].weighted != cands[ind2].weighted )
7125 	      return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7126 	   else
7127 	      return SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind1].expr)) - SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind2].expr));
7128 	}
7129 	
7130 	/** do branching or register branching candidates */
7131 	static
7132 	SCIP_RETCODE branching(
7133 	   SCIP*                 scip,               /**< SCIP data structure */
7134 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7135 	   SCIP_CONS**           conss,              /**< constraints to process */
7136 	   int                   nconss,             /**< number of constraints */
7137 	   SCIP_Real             maxrelconsviol,     /**< maximal scaled constraint violation */
7138 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
7139 	   SCIP_Longint          soltag,             /**< tag of solution */
7140 	   SCIP_RESULT*          result              /**< pointer to store the result of branching */
7141 	   )
7142 	{
7143 	   SCIP_CONSHDLRDATA* conshdlrdata;
7144 	   BRANCHCAND* cands;
7145 	   int ncands;
7146 	   SCIP_VAR* var;
7147 	   SCIP_NODE* downchild;
7148 	   SCIP_NODE* eqchild;
7149 	   SCIP_NODE* upchild;
7150 	
7151 	   assert(conshdlr != NULL);
7152 	   assert(result != NULL);
7153 	
7154 	   *result = SCIP_DIDNOTFIND;
7155 	
7156 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7157 	   assert(conshdlrdata != NULL);
7158 	
7159 	   if( conshdlrdata->branchexternal )
7160 	   {
7161 	      /* just register branching candidates as external */
7162 	      SCIP_Bool success;
7163 	
7164 	      SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7165 	      if( success )
7166 	         *result = SCIP_INFEASIBLE;
7167 	
7168 	      return SCIP_OKAY;
7169 	   }
7170 	
7171 	   /* collect branching candidates and their auxviol-score */
7172 	   SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip)) );
7173 	   SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7174 	
7175 	   /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7176 	    * we will return here and let the fallbacks in consEnfo() decide how to proceed
7177 	    */
7178 	   if( ncands == 0 )
7179 	      goto TERMINATE;
7180 	
7181 	   if( ncands > 1 )
7182 	   {
7183 	      /* if there are more than one candidate, then compute scores and select */
7184 	      int* perm;
7185 	      int c;
7186 	      int left;
7187 	      int right;
7188 	      SCIP_Real threshold;
7189 	
7190 	      /* compute additional scores on branching candidates and weighted score */
7191 	      scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7192 	
7193 	      /* sort candidates by weighted score */
7194 	      SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7195 	      SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7196 	
7197 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7198 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7199 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7200 	
7201 	      /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score)  candidate */
7202 	      left = 0;
7203 	      right = ncands - 1;
7204 	      threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7205 	      while( left < right )
7206 	      {
7207 	         int mid = (left + right) / 2;
7208 	         if( cands[perm[mid]].weighted >= threshold )
7209 	            left = mid + 1;
7210 	         else
7211 	            right = mid;
7212 	      }
7213 	      assert(left <= ncands);
7214 	
7215 	      if( left < ncands )
7216 	      {
7217 	         if( cands[perm[left]].weighted >= threshold )
7218 	         {
7219 	            assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7220 	            ncands = left + 1;
7221 	         }
7222 	         else
7223 	         {
7224 	            assert(cands[perm[left]].weighted < threshold);
7225 	            ncands = left;
7226 	         }
7227 	      }
7228 	      assert(ncands > 0);
7229 	
7230 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7231 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7232 	         SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7233 	
7234 	      if( ncands > 1 )
7235 	      {
7236 	         /* choose at random from candidates 0..ncands-1 */
7237 	         if( conshdlrdata->branchrandnumgen == NULL )
7238 	         {
7239 	            SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7240 	         }
7241 	         c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7242 	         var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7243 	      }
7244 	      else
7245 	         var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7246 	
7247 	      SCIPfreeBufferArray(scip, &perm);
7248 	   }
7249 	   else
7250 	   {
7251 	      var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7252 	   }
7253 	   assert(var != NULL);
7254 	
7255 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7256 	            SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); )
7257 	
7258 	   SCIP_CALL( SCIPbranchVarVal(scip, var, SCIPgetBranchingPoint(scip, var, SCIP_INVALID), &downchild, &eqchild,
7259 	            &upchild) );
7260 	   if( downchild != NULL || eqchild != NULL || upchild != NULL )
7261 	      *result = SCIP_BRANCHED;
7262 	   else
7263 	      /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7264 	      *result = SCIP_REDUCEDDOM;
7265 	
7266 	 TERMINATE:
7267 	   SCIPfreeBufferArray(scip, &cands);
7268 	
7269 	   return SCIP_OKAY;
7270 	}
7271 	
7272 	/** call enforcement or estimate callback of nonlinear handler
7273 	 *
7274 	 * Calls the enforcement callback, if available.
7275 	 * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7276 	 *
7277 	 * If cut is weak, but estimator is not tight, tries to add branching candidates.
7278 	 */
7279 	static
7280 	SCIP_RETCODE enforceExprNlhdlr(
7281 	   SCIP*                 scip,               /**< SCIP main data structure */
7282 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7283 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
7284 	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
7285 	   SCIP_EXPR*            expr,               /**< expression */
7286 	   SCIP_NLHDLREXPRDATA*  nlhdlrexprdata,     /**< nonlinear handler data of expression */
7287 	   SCIP_SOL*             sol,                /**< solution to be separated (NULL for the LP solution) */
7288 	   SCIP_Real             auxvalue,           /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7289 	   SCIP_Bool             overestimate,       /**< whether the expression needs to be over- or underestimated */
7290 	   SCIP_Bool             separated,          /**< whether another nonlinear handler already added a cut for this expression */
7291 	   SCIP_Bool             allowweakcuts,      /**< whether we allow for weak cuts */
7292 	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement (and not just separation) */
7293 	   SCIP_RESULT*          result              /**< pointer to store the result */
7294 	   )
7295 	{
7296 	   assert(result != NULL);
7297 	
7298 	   /* call enforcement callback of the nlhdlr */
7299 	   SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7300 	            allowweakcuts, separated, inenforcement, result) );
7301 	
7302 	   /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7303 	   if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7304 	   {
7305 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    enfo of nlhdlr <%s> succeeded with result %d\n",
7306 	               SCIPnlhdlrGetName(nlhdlr), *result); )
7307 	      return SCIP_OKAY;
7308 	   }
7309 	   else
7310 	   {
7311 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7312 	   }
7313 	
7314 	   *result = SCIP_DIDNOTFIND;
7315 	
7316 	   /* now call the estimator callback of the nlhdlr */
7317 	   if( SCIPnlhdlrHasEstimate(nlhdlr) )
7318 	   {
7319 	      SCIP_VAR* auxvar;
7320 	      SCIP_Bool sepasuccess = FALSE;
7321 	      SCIP_Bool branchscoresuccess = FALSE;
7322 	      SCIP_PTRARRAY* rowpreps;
7323 	      int minidx;
7324 	      int maxidx;
7325 	      int r;
7326 	      SCIP_ROWPREP* rowprep;
7327 	
7328 	      SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7329 	
7330 	      auxvar = SCIPgetExprAuxVarNonlinear(expr);
7331 	      assert(auxvar != NULL);
7332 	
7333 	      SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7334 	               SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7335 	
7336 	      minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7337 	      maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7338 	
7339 	      assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7340 	
7341 	      if( !sepasuccess )
7342 	      {
7343 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s failed\n",
7344 	                  SCIPnlhdlrGetName(nlhdlr)); )
7345 	      }
7346 	
7347 	      for( r = minidx; r <= maxidx; ++r )
7348 	      {
7349 	         rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7350 	
7351 	         assert(rowprep != NULL);
7352 	         assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7353 	
7354 	         /* complete estimator to cut */
7355 	         SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7356 	
7357 	         /* add the cut and/or branching scores */
7358 	         SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7359 	               auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7360 	
7361 	         SCIPfreeRowprep(scip, &rowprep);
7362 	      }
7363 	
7364 	      SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7365 	   }
7366 	
7367 	   return SCIP_OKAY;
7368 	}
7369 	
7370 	/** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7371 	 *
7372 	 * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7373 	 */
7374 	static
7375 	SCIP_RETCODE enforceExpr(
7376 	   SCIP*                 scip,               /**< SCIP data structure */
7377 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraints handler */
7378 	   SCIP_CONS*            cons,               /**< nonlinear constraint */
7379 	   SCIP_EXPR*            expr,               /**< expression */
7380 	   SCIP_SOL*             sol,                /**< solution to separate, or NULL if LP solution should be used */
7381 	   SCIP_Longint          soltag,             /**< tag of solution */
7382 	   SCIP_Bool             allowweakcuts,      /**< whether we allow weak cuts */
7383 	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement (and not just separation) */
7384 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
7385 	   )
7386 	{
7387 	   SCIP_CONSHDLRDATA* conshdlrdata;
7388 	   SCIP_EXPR_OWNERDATA* ownerdata;
7389 	   SCIP_Real origviol;
7390 	   SCIP_Bool underestimate;
7391 	   SCIP_Bool overestimate;
7392 	   SCIP_Real auxviol;
7393 	   SCIP_Bool auxunderestimate;
7394 	   SCIP_Bool auxoverestimate;
7395 	   SCIP_RESULT hdlrresult;
7396 	   int e;
7397 	
7398 	   assert(scip != NULL);
7399 	   assert(expr != NULL);
7400 	   assert(result != NULL);
7401 	
7402 	   ownerdata = SCIPexprGetOwnerData(expr);
7403 	   assert(ownerdata != NULL);
7404 	   assert(ownerdata->auxvar != NULL);  /* there must be a variable attached to the expression in order to construct a cut here */
7405 	
7406 	   *result = SCIP_DIDNOTFIND;
7407 	
7408 	   /* make sure that this expression has been evaluated */
7409 	   SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7410 	
7411 	   /* decide whether under- or overestimate is required and get amount of violation */
7412 	   origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7413 	
7414 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7415 	   assert(conshdlrdata != NULL);
7416 	
7417 	   /* no sufficient violation w.r.t. the original variables -> skip expression */
7418 	   if( !overestimate && !underestimate )
7419 	   {
7420 	      return SCIP_OKAY;
7421 	   }
7422 	
7423 	   /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7424 	   for( e = 0; e < ownerdata->nenfos; ++e )
7425 	   {
7426 	      SCIP_NLHDLR* nlhdlr;
7427 	
7428 	      /* skip nlhdlr that do not want to participate in any separation */
7429 	      if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7430 	         continue;
7431 	
7432 	      nlhdlr = ownerdata->enfos[e]->nlhdlr;
7433 	      assert(nlhdlr != NULL);
7434 	
7435 	      /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7436 	      SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7437 	      ENFOLOG(
7438 	         SCIPinfoMessage(scip, enfologfile, "  expr ");
7439 	         SCIPprintExpr(scip, expr, enfologfile);
7440 	         SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7441 	            "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7442 	            SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7443 	      )
7444 	
7445 	      /* TODO if expr is root of constraint (consdata->expr == expr),
7446 	       * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7447 	       * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7448 	       * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7449 	       * so we should enforce in these auxiliaries first
7450 	       * if changing this here, we must also adapt analyzeViolation()
7451 	       */
7452 	
7453 	      auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7454 	      assert(auxviol >= 0.0);
7455 	
7456 	      /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7457 	      if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7458 	      {
7459 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7460 	                  "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7461 	                  SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7462 	
7463 	         /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7464 	         continue;
7465 	      }
7466 	
7467 	      /* 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 */
7468 	      if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7469 	      {
7470 	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7471 	                  "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7472 	                  underestimate, overestimate); )
7473 	
7474 	            /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7475 	         continue;
7476 	      }
7477 	
7478 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "   enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7479 	               "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7480 	               auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7481 	
7482 	      /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7483 	       * wants to be called for separation on this side, then call separation of nlhdlr
7484 	       */
7485 	      if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7486 	      {
7487 	         /* call the separation or estimation callback of the nonlinear handler for overestimation */
7488 	         hdlrresult = SCIP_DIDNOTFIND;
7489 	         SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7490 	            ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7491 	
7492 	         if( hdlrresult == SCIP_CUTOFF )
7493 	         {
7494 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    found a cutoff -> stop separation\n"); )
7495 	            *result = SCIP_CUTOFF;
7496 	            ownerdata->lastenforced = conshdlrdata->enforound;
7497 	            break;
7498 	         }
7499 	
7500 	         if( hdlrresult == SCIP_SEPARATED )
7501 	         {
7502 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7503 	            *result = SCIP_SEPARATED;
7504 	            ownerdata->lastenforced = conshdlrdata->enforound;
7505 	            /* TODO or should we give other nlhdlr another chance? (also #3070) */
7506 	            break;
7507 	         }
7508 	
7509 	         if( hdlrresult == SCIP_REDUCEDDOM )
7510 	         {
7511 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7512 	            *result = SCIP_REDUCEDDOM;
7513 	            ownerdata->lastenforced = conshdlrdata->enforound;
7514 	            /* TODO or should we always just stop here? */
7515 	         }
7516 	
7517 	         if( hdlrresult == SCIP_BRANCHED )
7518 	         {
7519 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7520 	            assert(inenforcement);
7521 	
7522 	            /* separation and domain reduction takes precedence over branching */
7523 	            assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7524 	            if( *result == SCIP_DIDNOTFIND )
7525 	               *result = SCIP_BRANCHED;
7526 	            ownerdata->lastenforced = conshdlrdata->enforound;
7527 	         }
7528 	      }
7529 	
7530 	      /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7531 	       * wants to be called for separation on this side, then call separation of nlhdlr
7532 	       */
7533 	      if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7534 	      {
7535 	         /* call the separation or estimation callback of the nonlinear handler for underestimation */
7536 	         hdlrresult = SCIP_DIDNOTFIND;
7537 	         SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7538 	            ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7539 	
7540 	         if( hdlrresult == SCIP_CUTOFF )
7541 	         {
7542 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    found a cutoff -> stop separation\n"); )
7543 	            *result = SCIP_CUTOFF;
7544 	            ownerdata->lastenforced = conshdlrdata->enforound;
7545 	            break;
7546 	         }
7547 	
7548 	         if( hdlrresult == SCIP_SEPARATED )
7549 	         {
7550 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7551 	            *result = SCIP_SEPARATED;
7552 	            ownerdata->lastenforced = conshdlrdata->enforound;
7553 	            /* TODO or should we give other nlhdlr another chance? (also #3070) */
7554 	            break;
7555 	         }
7556 	
7557 	         if( hdlrresult == SCIP_REDUCEDDOM )
7558 	         {
7559 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7560 	            *result = SCIP_REDUCEDDOM;
7561 	            ownerdata->lastenforced = conshdlrdata->enforound;
7562 	            /* TODO or should we always just stop here? */
7563 	         }
7564 	
7565 	         if( hdlrresult == SCIP_BRANCHED )
7566 	         {
7567 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7568 	            assert(inenforcement);
7569 	
7570 	            /* separation takes precedence over branching */
7571 	            assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7572 	            if( *result == SCIP_DIDNOTFIND )
7573 	               *result = SCIP_BRANCHED;
7574 	            ownerdata->lastenforced = conshdlrdata->enforound;
7575 	         }
7576 	      }
7577 	   }
7578 	
7579 	   return SCIP_OKAY;
7580 	}
7581 	
7582 	/** helper function to enforce a single constraint */
7583 	static
7584 	SCIP_RETCODE enforceConstraint(
7585 	   SCIP*                 scip,               /**< SCIP data structure */
7586 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7587 	   SCIP_CONS*            cons,               /**< constraint to process */
7588 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
7589 	   SCIP_Longint          soltag,             /**< tag of solution */
7590 	   SCIP_EXPRITER*        it,                 /**< expression iterator that we can just use here */
7591 	   SCIP_Bool             allowweakcuts,      /**< whether to allow weak cuts in this round */
7592 	   SCIP_Bool             inenforcement,      /**< whether to we are in enforcement, and not just separation */
7593 	   SCIP_RESULT*          result,             /**< pointer to update with result of the enforcing call */
7594 	   SCIP_Bool*            success             /**< buffer to store whether some enforcement took place */
7595 	   )
7596 	{
7597 	   SCIP_CONSDATA* consdata;
7598 	   SCIP_CONSHDLRDATA* conshdlrdata;
7599 	   SCIP_EXPR* expr;
7600 	
7601 	   assert(conshdlr != NULL);
7602 	   assert(cons != NULL);
7603 	   assert(it != NULL);
7604 	   assert(result != NULL);
7605 	   assert(success != NULL);
7606 	
7607 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7608 	   assert(conshdlrdata != NULL);
7609 	
7610 	   consdata = SCIPconsGetData(cons);
7611 	   assert(consdata != NULL);
7612 	   assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7613 	
7614 	   *success = FALSE;
7615 	
7616 	   if( inenforcement && !consdata->ispropagated )
7617 	   {
7618 	      /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7619 	       * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7620 	       * (TODO: nlhdlr tells us now whether they do and so we could skip).
7621 	       * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7622 	       * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7623 	       * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7624 	       * confuse the stalling check for how long to do separation).
7625 	       */
7626 	      SCIP_Bool infeasible;
7627 	      int ntightenings;
7628 	
7629 	      SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7630 	      if( infeasible )
7631 	      {
7632 	         *result = SCIP_CUTOFF;
7633 	         return SCIP_OKAY;
7634 	      }
7635 	      /* if we tightened an auxvar bound, we better communicate that */
7636 	      if( ntightenings > 0 )
7637 	         *result = SCIP_REDUCEDDOM;
7638 	   }
7639 	
7640 	   for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7641 	   {
7642 	      SCIP_EXPR_OWNERDATA* ownerdata;
7643 	      SCIP_RESULT resultexpr;
7644 	
7645 	      ownerdata = SCIPexprGetOwnerData(expr);
7646 	      assert(ownerdata != NULL);
7647 	
7648 	      /* we can only enforce if there is an auxvar to compare with */
7649 	      if( ownerdata->auxvar == NULL )
7650 	         continue;
7651 	
7652 	      assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7653 	      if( ownerdata->lastenforced == conshdlrdata->enforound )
7654 	      {
7655 	         ENFOLOG(
7656 	            SCIPinfoMessage(scip, enfologfile, "  skip expr ");
7657 	            SCIPprintExpr(scip, expr, enfologfile);
7658 	            SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7659 	         )
7660 	         *success = TRUE;
7661 	         continue;
7662 	      }
7663 	
7664 	      SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7665 	
7666 	      /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7667 	      assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7668 	      if( ownerdata->lastenforced == conshdlrdata->enforound )
7669 	         *success = TRUE;
7670 	
7671 	      if( resultexpr == SCIP_CUTOFF )
7672 	      {
7673 	         *result = SCIP_CUTOFF;
7674 	         break;
7675 	      }
7676 	
7677 	      if( resultexpr == SCIP_SEPARATED )
7678 	         *result = SCIP_SEPARATED;
7679 	
7680 	      if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7681 	         *result = SCIP_REDUCEDDOM;
7682 	
7683 	      if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7684 	         *result = SCIP_BRANCHED;
7685 	   }
7686 	
7687 	   return SCIP_OKAY;
7688 	}
7689 	
7690 	/** try to separate violated constraints and, if in enforcement, register branching scores
7691 	 *
7692 	 * Sets result to
7693 	 * - SCIP_DIDNOTFIND, if nothing of the below has been done
7694 	 * - SCIP_CUTOFF, if node can be cutoff,
7695 	 * - SCIP_SEPARATED, if a cut has been added,
7696 	 * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7697 	 * - SCIP_BRANCHED, if branching has been done,
7698 	 * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7699 	 * - SCIP_INFEASIBLE, if external branching candidates were registered
7700 	 */
7701 	static
7702 	SCIP_RETCODE enforceConstraints(
7703 	   SCIP*                 scip,               /**< SCIP data structure */
7704 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7705 	   SCIP_CONS**           conss,              /**< constraints to process */
7706 	   int                   nconss,             /**< number of constraints */
7707 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
7708 	   SCIP_Longint          soltag,             /**< tag of solution */
7709 	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement, and not just separation */
7710 	   SCIP_Real             maxrelconsviol,     /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7711 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
7712 	   )
7713 	{
7714 	   SCIP_CONSHDLRDATA* conshdlrdata;
7715 	   SCIP_EXPRITER* it;
7716 	   SCIP_Bool consenforced;  /* whether any expression in constraint could be enforced */
7717 	   int c;
7718 	
7719 	   assert(conshdlr != NULL);
7720 	   assert(conss != NULL || nconss == 0);
7721 	   assert(result != NULL);
7722 	
7723 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
7724 	   assert(conshdlrdata != NULL);
7725 	
7726 	   /* increase tag to tell whether branching scores in expression belong to this sweep
7727 	    * and which expressions have already been enforced in this sweep
7728 	    * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7729 	    */
7730 	   ++(conshdlrdata->enforound);
7731 	
7732 	   *result = SCIP_DIDNOTFIND;
7733 	
7734 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7735 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, TRUE) );
7736 	
7737 	   for( c = 0; c < nconss; ++c )
7738 	   {
7739 	      assert(conss != NULL && conss[c] != NULL);
7740 	
7741 	      /* skip constraints that are not enabled or deleted */
7742 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7743 	         continue;
7744 	      assert(SCIPconsIsActive(conss[c]));
7745 	
7746 	      /* skip constraints that have separation disabled if we are only in separation */
7747 	      if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7748 	         continue;
7749 	
7750 	      /* skip non-violated constraints */
7751 	      if( !isConsViolated(scip, conss[c]) )
7752 	         continue;
7753 	
7754 	      ENFOLOG(
7755 	      {
7756 	         SCIP_CONSDATA* consdata;
7757 	         int i;
7758 	         consdata = SCIPconsGetData(conss[c]);
7759 	         assert(consdata != NULL);
7760 	         SCIPinfoMessage(scip, enfologfile, " constraint ");
7761 	         SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7762 	         SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7763 	         for( i = 0; i < consdata->nvarexprs; ++i )
7764 	         {
7765 	            SCIP_VAR* var;
7766 	            var = SCIPgetVarExprVar(consdata->varexprs[i]);
7767 	            SCIPinfoMessage(scip, enfologfile, "  %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7768 	                  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7769 	         }
7770 	      })
7771 	
7772 	      SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, result, &consenforced) );
7773 	
7774 	      if( *result == SCIP_CUTOFF )
7775 	         break;
7776 	
7777 	      if( !consenforced && inenforcement )
7778 	      {
7779 	         SCIP_Real viol;
7780 	
7781 	         SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7782 	         if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7783 	         {
7784 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7785 	                     "cuts allowed\n", SCIPconsGetName(conss[c])); )
7786 	
7787 	            SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, result, &consenforced) );
7788 	
7789 	            if( consenforced )
7790 	               ++conshdlrdata->nweaksepa;  /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7791 	
7792 	            if( *result == SCIP_CUTOFF )
7793 	               break;
7794 	         }
7795 	      }
7796 	   }
7797 	
7798 	   SCIPfreeExpriter(&it);
7799 	
7800 	   ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7801 	
7802 	   /* if having branching scores, then propagate them from expressions with children to variable expressions */
7803 	   if( *result == SCIP_BRANCHED )
7804 	   {
7805 	      /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7806 	       * branching
7807 	       */
7808 	      SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7809 	
7810 	      /* branching should either have branched: result == SCIP_BRANCHED,
7811 	       * or fixed a variable: result == SCIP_REDUCEDDOM,
7812 	       * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7813 	       * or have not done anything: result == SCIP_DIDNOTFIND
7814 	       */
7815 	      assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7816 	   }
7817 	
7818 	   ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7819 	
7820 	   return SCIP_OKAY;
7821 	}
7822 	
7823 	/** collect (and print (if debugging enfo)) information on violation in expressions
7824 	 *
7825 	 * assumes that constraint violations have been computed
7826 	 */
7827 	static
7828 	SCIP_RETCODE analyzeViolation(
7829 	   SCIP*                 scip,               /**< SCIP data structure */
7830 	   SCIP_CONS**           conss,              /**< constraints */
7831 	   int                   nconss,             /**< number of constraints */
7832 	   SCIP_SOL*             sol,                /**< solution to separate, or NULL if LP solution should be used */
7833 	   SCIP_Longint          soltag,             /**< tag of solution */
7834 	   SCIP_Real*            maxabsconsviol,     /**< buffer to store maximal absolute violation of constraints */
7835 	   SCIP_Real*            maxrelconsviol,     /**< buffer to store maximal relative violation of constraints */
7836 	   SCIP_Real*            minauxviol,         /**< buffer to store minimal (nonzero) violation of auxiliaries */
7837 	   SCIP_Real*            maxauxviol,         /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7838 	   SCIP_Real*            maxvarboundviol     /**< buffer to store maximal violation of variable bounds */
7839 	   )
7840 	{
7841 	   SCIP_CONSDATA* consdata;
7842 	   SCIP_EXPRITER* it;
7843 	   SCIP_EXPR* expr;
7844 	   SCIP_Real v;
7845 	   int c;
7846 	
7847 	   assert(conss != NULL || nconss == 0);
7848 	   assert(maxabsconsviol != NULL);
7849 	   assert(maxrelconsviol != NULL);
7850 	   assert(maxauxviol != NULL);
7851 	   assert(maxvarboundviol != NULL);
7852 	
7853 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7854 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
7855 	
7856 	   *maxabsconsviol = 0.0;
7857 	   *maxrelconsviol = 0.0;
7858 	   *minauxviol = SCIPinfinity(scip);
7859 	   *maxauxviol = 0.0;
7860 	   *maxvarboundviol = 0.0;
7861 	
7862 	   for( c = 0; c < nconss; ++c )
7863 	   {
7864 	      assert(conss != NULL && conss[c] != NULL);
7865 	
7866 	      consdata = SCIPconsGetData(conss[c]);
7867 	      assert(consdata != NULL);
7868 	
7869 	      /* skip constraints that are not enabled, deleted, or have separation disabled */
7870 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7871 	         continue;
7872 	      assert(SCIPconsIsActive(conss[c]));
7873 	
7874 	      v = getConsAbsViolation(conss[c]);
7875 	      *maxabsconsviol = MAX(*maxabsconsviol, v);
7876 	
7877 	      /* skip non-violated constraints */
7878 	      if( !isConsViolated(scip, conss[c]) )
7879 	         continue;
7880 	
7881 	      SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
7882 	      *maxrelconsviol = MAX(*maxrelconsviol, v);
7883 	
7884 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7885 	      {
7886 	         SCIP_EXPR_OWNERDATA* ownerdata;
7887 	         SCIP_Real auxvarvalue;
7888 	         SCIP_Real auxvarlb;
7889 	         SCIP_Real auxvarub;
7890 	         SCIP_Bool violunder;
7891 	         SCIP_Bool violover;
7892 	         SCIP_Real origviol;
7893 	         SCIP_Real auxviol;
7894 	         int e;
7895 	
7896 	         ownerdata = SCIPexprGetOwnerData(expr);
7897 	         assert(ownerdata != NULL);
7898 	
7899 	         if( ownerdata->auxvar == NULL )
7900 	         {
7901 	            /* check violation of variable bounds of original variable */
7902 	            if( SCIPisExprVar(scip, expr) )
7903 	            {
7904 	               SCIP_VAR* var;
7905 	               var = SCIPgetVarExprVar(expr);
7906 	               auxvarvalue = SCIPgetSolVal(scip, sol, var);
7907 	               auxvarlb = SCIPvarGetLbLocal(var);
7908 	               auxvarub = SCIPvarGetUbLocal(var);
7909 	
7910 	               origviol = 0.0;
7911 	               if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
7912 	                  origviol = auxvarlb - auxvarvalue;
7913 	               else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
7914 	                  origviol = auxvarvalue - auxvarub;
7915 	               if( origviol <= 0.0 )
7916 	                  continue;
7917 	
7918 	               *maxvarboundviol = MAX(*maxvarboundviol, origviol);
7919 	
7920 	               ENFOLOG(
7921 	               SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
7922 	               if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
7923 	                  SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
7924 	               if( auxvarub < auxvarvalue && !SCIPisInfinity(scip,  auxvarub) )
7925 	                  SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
7926 	               SCIPinfoMessage(scip, enfologfile, "\n");
7927 	               )
7928 	            }
7929 	
7930 	            continue;
7931 	         }
7932 	
7933 	         auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
7934 	         auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
7935 	         auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
7936 	
7937 	         /* check violation of variable bounds of auxiliary variable */
7938 	         if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
7939 	            *maxvarboundviol = auxvarlb - auxvarvalue;
7940 	         else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip,  auxvarub) )
7941 	            *maxvarboundviol = auxvarvalue - auxvarub;
7942 	
7943 	         origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
7944 	
7945 	         ENFOLOG(
7946 	         if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
7947 	         {
7948 	            SCIPinfoMessage(scip, enfologfile, "expr ");
7949 	            SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
7950 	            SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
7951 	
7952 	            SCIPinfoMessage(scip, enfologfile, "  auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
7953 	            if( origviol > 0.0 )
7954 	               SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
7955 	            if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
7956 	               SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
7957 	            if( auxvarub < auxvarvalue && !SCIPisInfinity(scip,  auxvarub) )
7958 	               SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
7959 	            SCIPinfoMessage(scip, enfologfile, "\n");
7960 	         }
7961 	         )
7962 	
7963 	         /* no violation w.r.t. the original variables -> skip expression */
7964 	         if( origviol == 0.0 )
7965 	            continue;
7966 	
7967 	         /* compute aux-violation for each nonlinear handlers */
7968 	         for( e = 0; e < ownerdata->nenfos; ++e )
7969 	         {
7970 	            SCIP_NLHDLR* nlhdlr;
7971 	
7972 	            /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
7973 	            if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7974 	               continue;
7975 	
7976 	            nlhdlr = ownerdata->enfos[e]->nlhdlr;
7977 	            assert(nlhdlr != NULL);
7978 	
7979 	            /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7980 	            SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7981 	
7982 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "  nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
7983 	
7984 	            auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
7985 	
7986 	            if( auxviol > 0.0 )
7987 	            {
7988 	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
7989 	               *maxauxviol = MAX(*maxauxviol, auxviol);
7990 	               *minauxviol = MIN(*minauxviol, auxviol);
7991 	            }
7992 	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
7993 	         }
7994 	      }
7995 	   }
7996 	
7997 	   SCIPfreeExpriter(&it);
7998 	
7999 	   return SCIP_OKAY;
8000 	} /*lint !e715*/
8001 	
8002 	/** enforcement of constraints called by enfolp and enforelax */
8003 	static
8004 	SCIP_RETCODE consEnfo(
8005 	   SCIP*                 scip,               /**< SCIP data structure */
8006 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
8007 	   SCIP_CONS**           conss,              /**< constraints to process */
8008 	   int                   nconss,             /**< number of constraints */
8009 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
8010 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
8011 	   )
8012 	{
8013 	   SCIP_CONSHDLRDATA* conshdlrdata;
8014 	   SCIP_Real maxabsconsviol;
8015 	   SCIP_Real maxrelconsviol;
8016 	   SCIP_Real minauxviol;
8017 	   SCIP_Real maxauxviol;
8018 	   SCIP_Real maxvarboundviol;
8019 	   SCIP_Longint soltag;
8020 	   int nnotify;
8021 	   int c;
8022 	
8023 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8024 	   assert(conshdlr != NULL);
8025 	
8026 	   soltag = SCIPgetExprNewSoltag(scip);
8027 	
8028 	   *result = SCIP_FEASIBLE;
8029 	   for( c = 0; c < nconss; ++c )
8030 	   {
8031 	      SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8032 	
8033 	      if( isConsViolated(scip, conss[c]) )
8034 	         *result = SCIP_INFEASIBLE;
8035 	   }
8036 	
8037 	   if( *result == SCIP_FEASIBLE )
8038 	   {
8039 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8040 	               SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8041 	      return SCIP_OKAY;
8042 	   }
8043 	
8044 	   SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8045 	            &minauxviol, &maxauxviol, &maxvarboundviol) );
8046 	
8047 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8048 	            "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8049 	            SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8050 	            maxvarboundviol, SCIPgetLPFeastol(scip)); )
8051 	
8052 	   assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8053 	
8054 	   /* try to propagate */
8055 	   if( conshdlrdata->propinenforce )
8056 	   {
8057 	      SCIP_RESULT propresult;
8058 	      int nchgbds = 0;
8059 	
8060 	      SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8061 	
8062 	      if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8063 	      {
8064 	         *result = propresult;
8065 	         return SCIP_OKAY;
8066 	      }
8067 	   }
8068 	
8069 	   /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8070 	    * all violated expr/auxvar in violated constraints)
8071 	    */
8072 	   if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8073 	         sol == NULL )
8074 	   {
8075 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8076 	      ++conshdlrdata->ntightenlp;
8077 	
8078 	      *result = SCIP_SOLVELP;
8079 	
8080 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8081 	               "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8082 	
8083 	      return SCIP_OKAY;
8084 	   }
8085 	
8086 	   /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8087 	    * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8088 	    */
8089 	   if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8090 	   {
8091 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8092 	      ++conshdlrdata->ntightenlp;
8093 	
8094 	      *result = SCIP_SOLVELP;
8095 	
8096 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8097 	
8098 	      return SCIP_OKAY;
8099 	   }
8100 	
8101 	   SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8102 	
8103 	   if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8104 	         *result == SCIP_INFEASIBLE )
8105 	      return SCIP_OKAY;
8106 	
8107 	   assert(*result == SCIP_DIDNOTFIND);
8108 	
8109 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8110 	            "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8111 	
8112 	   if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8113 	   {
8114 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8115 	      ++conshdlrdata->ntightenlp;
8116 	
8117 	      *result = SCIP_SOLVELP;
8118 	
8119 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8120 	               "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8121 	
8122 	      return SCIP_OKAY;
8123 	   }
8124 	
8125 	   if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8126 	            SCIPgetLPFeastol(scip)) && sol == NULL )
8127 	   {
8128 	      /* try whether tighten the LP feasibility tolerance could help
8129 	       * maybe it is just some cut that hasn't been taken into account sufficiently
8130 	       * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8131 	       * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8132 	       * until the LP feastol reaches epsilon
8133 	       * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8134 	       * when maxauxviol is above LP feastol)
8135 	       */
8136 	      SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8137 	      ++conshdlrdata->ndesperatetightenlp;
8138 	
8139 	      *result = SCIP_SOLVELP;
8140 	
8141 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8142 	
8143 	      return SCIP_OKAY;
8144 	   }
8145 	
8146 	   /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8147 	   if( !conshdlrdata->propinenforce )
8148 	   {
8149 	      SCIP_RESULT propresult;
8150 	      int nchgbds = 0;
8151 	
8152 	      SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8153 	
8154 	      if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8155 	      {
8156 	         *result = propresult;
8157 	         return SCIP_OKAY;
8158 	      }
8159 	   }
8160 	
8161 	   /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8162 	    * now look if we find any unfixed variable that we could still branch on
8163 	    */
8164 	   SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8165 	
8166 	   if( nnotify > 0 )
8167 	   {
8168 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8169 	      ++conshdlrdata->ndesperatebranch;
8170 	
8171 	      *result = SCIP_INFEASIBLE;  /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8172 	
8173 	      return SCIP_OKAY;
8174 	   }
8175 	
8176 	   /* if everything is fixed in violated constraints, then let's cut off the node
8177 	    * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8178 	    *   result may not be conclusive (when constraint violations are small)
8179 	    * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8180 	    *   sufficiently (see st_e40)
8181 	    * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8182 	    *   not "desperate", but a pretty obvious thing to do
8183 	    */
8184 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8185 	   *result = SCIP_CUTOFF;
8186 	
8187 	   /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8188 	   if( !SCIPisZero(scip, maxvarboundviol) )
8189 	      ++conshdlrdata->ndesperatecutoff;
8190 	
8191 	   return SCIP_OKAY;
8192 	}
8193 	
8194 	/** separation for all violated constraints to be used by SEPA callbacks */
8195 	static
8196 	SCIP_RETCODE consSepa(
8197 	   SCIP*                 scip,               /**< SCIP data structure */
8198 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
8199 	   SCIP_CONS**           conss,              /**< constraints to process */
8200 	   int                   nconss,             /**< number of constraints */
8201 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
8202 	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
8203 	   )
8204 	{
8205 	   SCIP_Longint soltag;
8206 	   SCIP_Bool haveviol = FALSE;
8207 	   int c;
8208 	
8209 	   *result = SCIP_DIDNOTFIND;
8210 	
8211 	   soltag = SCIPgetExprNewSoltag(scip);
8212 	
8213 	   /* compute violations */
8214 	   for( c = 0; c < nconss; ++c )
8215 	   {
8216 	      assert(conss[c] != NULL);
8217 	
8218 	      /* skip constraints that are not enabled, deleted, or have separation disabled */
8219 	      if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8220 	         continue;
8221 	      assert(SCIPconsIsActive(conss[c]));
8222 	
8223 	      SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8224 	
8225 	      if( isConsViolated(scip, conss[c]) )
8226 	         haveviol = TRUE;
8227 	   }
8228 	
8229 	   /* if none of our constraints are violated, don't attempt separation */
8230 	   if( !haveviol )
8231 	   {
8232 	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8233 	      return SCIP_OKAY;
8234 	   }
8235 	
8236 	   ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8237 	
8238 	   /* call separation */
8239 	   SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8240 	
8241 	   return SCIP_OKAY;
8242 	}
8243 	
8244 	/** hash key retrieval function for bilinear term entries */
8245 	static
8246 	SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8247 	{  /*lint --e{715}*/
8248 	   SCIP_CONSHDLRDATA* conshdlrdata;
8249 	   int idx;
8250 	
8251 	   conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8252 	   assert(conshdlrdata != NULL);
8253 	
8254 	   idx = ((int)(size_t)elem) - 1;
8255 	   assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8256 	
8257 	   return (void*)&conshdlrdata->bilinterms[idx];
8258 	}
8259 	
8260 	/** returns TRUE iff the bilinear term entries are equal */
8261 	static
8262 	SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8263 	{  /*lint --e{715}*/
8264 	   SCIP_CONSNONLINEAR_BILINTERM* entry1;
8265 	   SCIP_CONSNONLINEAR_BILINTERM* entry2;
8266 	
8267 	   /* get corresponding entries */
8268 	   entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8269 	   entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8270 	   assert(entry1->x != NULL && entry1->y != NULL);
8271 	   assert(entry2->x != NULL && entry2->y != NULL);
8272 	   assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8273 	   assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8274 	
8275 	   return entry1->x == entry2->x && entry1->y == entry2->y;
8276 	}
8277 	
8278 	/** returns the hash value of the key */
8279 	static
8280 	SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8281 	{  /*lint --e{715}*/
8282 	   SCIP_CONSNONLINEAR_BILINTERM* entry;
8283 	
8284 	   entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8285 	   assert(entry->x != NULL && entry->y != NULL);
8286 	   assert(SCIPvarCompare(entry->x, entry->y) < 1);
8287 	
8288 	   return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8289 	}
8290 	
8291 	/** compare two auxiliary expressions
8292 	 *
8293 	 *  Compares auxiliary variables, followed by coefficients, and then constants.
8294 	 */
8295 	static
8296 	SCIP_DECL_SORTPTRCOMP(auxexprComp)
8297 	{
8298 	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr1 = (SCIP_CONSNONLINEAR_AUXEXPR*)elem1;
8299 	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr2 = (SCIP_CONSNONLINEAR_AUXEXPR*)elem2;
8300 	   int compvars;
8301 	   int i;
8302 	
8303 	   /* compare the auxiliary variables */
8304 	   compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8305 	
8306 	   if( compvars != 0 )
8307 	      return compvars;
8308 	
8309 	   /* compare the coefficients and constants */
8310 	   for( i = 0; i < 3; ++i )
8311 	   {
8312 	      if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8313 	         return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8314 	   }
8315 	
8316 	   return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8317 	}
8318 	
8319 	/* add an auxiliary expression to a bilinear term */
8320 	static
8321 	SCIP_RETCODE bilinTermAddAuxExpr(
8322 	   SCIP*                 scip,               /**< SCIP data structure */
8323 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< nonlinear constraint handler data */
8324 	   SCIP_CONSNONLINEAR_BILINTERM* term,       /**< bilinear term */
8325 	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr,      /**< auxiliary expression to add */
8326 	   SCIP_Bool*            added               /**< pointer to store whether auxexpr has been added */
8327 	   )
8328 	{
8329 	   SCIP_Bool found;
8330 	   int pos;
8331 	   int i;
8332 	
8333 	   *added = FALSE;
8334 	
8335 	   /* check if auxexpr has already been added to term */
8336 	   if( term->nauxexprs == 0 )
8337 	   {
8338 	      found = FALSE;
8339 	      pos = 0;
8340 	   }
8341 	   else
8342 	   {
8343 	      found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8344 	   }
8345 	
8346 	   if( !found )
8347 	   {
8348 	      if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8349 	         return SCIP_OKAY;
8350 	
8351 	      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8352 	      assert(term->auxexprssize >= term->nauxexprs + 1);
8353 	
8354 	      /* insert expression at the correct position */
8355 	      for( i = term->nauxexprs; i > pos; --i )
8356 	      {
8357 	         term->aux.exprs[i] = term->aux.exprs[i-1];
8358 	      }
8359 	      term->aux.exprs[pos] = auxexpr;
8360 	      ++(term->nauxexprs);
8361 	      *added = TRUE;
8362 	   }
8363 	   else
8364 	   {
8365 	      term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8366 	      term->aux.exprs[pos]->overestimate  |= auxexpr->overestimate;
8367 	   }
8368 	
8369 	   return SCIP_OKAY;
8370 	}
8371 	
8372 	/** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8373 	static
8374 	SCIP_RETCODE bilinearTermsInsertAll(
8375 	   SCIP*                 scip,               /**< SCIP data structure */
8376 	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
8377 	   SCIP_CONS**           conss,              /**< nonlinear constraints */
8378 	   int                   nconss              /**< total number of nonlinear constraints */
8379 	   )
8380 	{
8381 	   SCIP_CONSHDLRDATA* conshdlrdata;
8382 	   SCIP_EXPRITER* it;
8383 	   int c;
8384 	
8385 	   assert(conss != NULL || nconss == 0);
8386 	
8387 	   if( nconss == 0 )
8388 	      return SCIP_OKAY;
8389 	
8390 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8391 	   assert(conshdlrdata != NULL);
8392 	
8393 	   /* check whether the bilinear terms have been stored already */
8394 	   if( conshdlrdata->bilinterms != NULL )
8395 	      return SCIP_OKAY;
8396 	
8397 	   /* create and initialize iterator */
8398 	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8399 	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
8400 	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR);
8401 	
8402 	   /* iterate through all constraints */
8403 	   for( c = 0; c < nconss; ++c )
8404 	   {
8405 	      SCIP_CONSDATA* consdata;
8406 	      SCIP_EXPR* expr;
8407 	
8408 	      assert(conss != NULL && conss[c] != NULL);
8409 	      consdata = SCIPconsGetData(conss[c]);
8410 	      assert(consdata != NULL);
8411 	
8412 	      /* iterate through all expressions */
8413 	      for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8414 	      {
8415 	         SCIP_EXPR** children = SCIPexprGetChildren(expr);
8416 	         SCIP_VAR* x = NULL;
8417 	         SCIP_VAR* y = NULL;
8418 	
8419 	         /* check whether the expression is of the form f(..)^2 */
8420 	         if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8421 	         {
8422 	            x = SCIPgetExprAuxVarNonlinear(children[0]);
8423 	            y = x;
8424 	         }
8425 	         /* check whether the expression is of the form f(..) * g(..) */
8426 	         else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8427 	         {
8428 	            x = SCIPgetExprAuxVarNonlinear(children[0]);
8429 	            y = SCIPgetExprAuxVarNonlinear(children[1]);
8430 	         }
8431 	
8432 	         /* add variables to the hash table */
8433 	         if( x != NULL && y != NULL )
8434 	         {
8435 	            SCIP_CALL( SCIPinsertBilinearTermExistingNonlinear(scip, conshdlr, x, y, SCIPgetExprAuxVarNonlinear(expr),
8436 	               SCIPgetExprNLocksPosNonlinear(expr), SCIPgetExprNLocksNegNonlinear(expr)) );
8437 	         }
8438 	      }
8439 	   }
8440 	
8441 	   /* release iterator */
8442 	   SCIPfreeExpriter(&it);
8443 	
8444 	   return SCIP_OKAY;
8445 	}
8446 	
8447 	/** store x, y and the locks in a new bilinear term */
8448 	static
8449 	SCIP_RETCODE bilinearTermsInsertEntry(
8450 	   SCIP*                 scip,               /**< SCIP data structure */
8451 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
8452 	   SCIP_VAR*             x,                  /**< the first variable */
8453 	   SCIP_VAR*             y,                  /**< the second variable */
8454 	   int                   nlockspos,          /**< number of positive locks of the bilinear term */
8455 	   int                   nlocksneg,          /**< number of negative locks of the bilinear term */
8456 	   int*                  idx,                /**< pointer to store the position of the term in bilinterms array */
8457 	   SCIP_Bool             existing            /**< whether the term exists explicitly in the problem */
8458 	   )
8459 	{
8460 	   SCIP_CONSHDLRDATA* conshdlrdata;
8461 	   SCIP_CONSNONLINEAR_BILINTERM* term;
8462 	
8463 	   assert(conshdlr != NULL);
8464 	   assert(x != NULL);
8465 	   assert(y != NULL);
8466 	   assert(nlockspos >= 0);
8467 	   assert(nlocksneg >= 0);
8468 	
8469 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8470 	   assert(conshdlrdata != NULL);
8471 	
8472 	   /* ensure that x.index <= y.index */
8473 	   if( SCIPvarCompare(x, y) == 1 )
8474 	   {
8475 	      SCIPswapPointers((void**)&x, (void**)&y);
8476 	   }
8477 	   assert(SCIPvarCompare(x, y) < 1);
8478 	
8479 	   *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8480 	
8481 	   /* update or create the term */
8482 	   if( *idx >= 0 )
8483 	   { /* the term has already been added */
8484 	      assert(conshdlrdata->bilinterms[*idx].x == x);
8485 	      assert(conshdlrdata->bilinterms[*idx].y == y);
8486 	
8487 	      /* get term and add locks */
8488 	      term = &conshdlrdata->bilinterms[*idx];
8489 	      assert(existing <= term->existing); /* implicit terms are added after existing ones */
8490 	      term->nlockspos += nlockspos;
8491 	      term->nlocksneg += nlocksneg;
8492 	   }
8493 	   else
8494 	   { /* this is the first time we encounter this product */
8495 	      /* ensure size of bilinterms array */
8496 	      SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8497 	
8498 	      *idx = conshdlrdata->nbilinterms;
8499 	
8500 	      /* get term and set values in the created bilinear term */
8501 	      term = &conshdlrdata->bilinterms[*idx];
8502 	      assert(term != NULL);
8503 	      term->x = x;
8504 	      term->y = y;
8505 	      term->nauxexprs = 0;
8506 	      term->auxexprssize = 0;
8507 	      term->nlockspos = nlockspos;
8508 	      term->nlocksneg = nlocksneg;
8509 	      term->existing = existing;
8510 	      if( existing )
8511 	         term->aux.var = NULL;
8512 	      else
8513 	         term->aux.exprs = NULL;
8514 	
8515 	      /* increase the total number of bilinear terms */
8516 	      ++(conshdlrdata->nbilinterms);
8517 	
8518 	      /* save to the hashtable */
8519 	      if( conshdlrdata->bilinhashtable == NULL )
8520 	      {
8521 	         SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8522 	               bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8523 	               (void*)conshdlrdata) );
8524 	      }
8525 	      assert(conshdlrdata->bilinhashtable != NULL);
8526 	
8527 	      /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8528 	       * because zero can not be inserted into hash table
8529 	       */
8530 	      SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8531 	
8532 	      /* capture product variables */
8533 	      SCIP_CALL( SCIPcaptureVar(scip, x) );
8534 	      SCIP_CALL( SCIPcaptureVar(scip, y) );
8535 	   }
8536 	
8537 	   return SCIP_OKAY;
8538 	}
8539 	
8540 	/** frees array of bilinear terms and hash table */
8541 	static
8542 	SCIP_RETCODE bilinearTermsFree(
8543 	   SCIP*                 scip,               /**< SCIP data structure */
8544 	   SCIP_CONSHDLRDATA*    conshdlrdata        /**< constraint handler data */
8545 	   )
8546 	{
8547 	   int i;
8548 	   int j;
8549 	
8550 	   assert(conshdlrdata != NULL);
8551 	
8552 	   /* check whether bilinear terms have been stored */
8553 	   if( conshdlrdata->bilinterms == NULL )
8554 	   {
8555 	      assert(conshdlrdata->bilinterms == NULL);
8556 	      assert(conshdlrdata->nbilinterms == 0);
8557 	      assert(conshdlrdata->bilintermssize == 0);
8558 	
8559 	      return SCIP_OKAY;
8560 	   }
8561 	
8562 	   /* release variables */
8563 	   for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8564 	   {
8565 	      SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8566 	      SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8567 	
8568 	      for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8569 	      {
8570 	         if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8571 	         {
8572 	            SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8573 	         }
8574 	         SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8575 	      }
8576 	
8577 	      if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8578 	      {
8579 	         SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8580 	         continue;
8581 	      }
8582 	
8583 	      /* the rest is for simple terms with a single auxvar */
8584 	
8585 	      /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8586 	      if( conshdlrdata->bilinterms[i].aux.var != NULL )
8587 	      {
8588 	         SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8589 	      }
8590 	   }
8591 	
8592 	   /* free hash table */
8593 	   if( conshdlrdata->bilinhashtable != NULL )
8594 	   {
8595 	      SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8596 	   }
8597 	
8598 	   /* free bilinterms array; reset counters */
8599 	   SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8600 	   conshdlrdata->nbilinterms = 0;
8601 	   conshdlrdata->bilintermssize = 0;
8602 	
8603 	   return SCIP_OKAY;
8604 	}
8605 	
8606 	/*
8607 	 * vertex polyhedral separation
8608 	 */
8609 	
8610 	/** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8611 	static
8612 	SCIP_RETCODE buildVertexPolyhedralSeparationLP(
8613 	   SCIP*                 scip,               /**< SCIP data structure */
8614 	   int                   nvars,              /**< number of (unfixed) variables in vertex-polyhedral functions */
8615 	   SCIP_LPI**            lp                  /**< pointer to store created LP */
8616 	   )
8617 	{
8618 	   SCIP_Real* obj;
8619 	   SCIP_Real* lb;
8620 	   SCIP_Real* ub;
8621 	   SCIP_Real* val;
8622 	   int* beg;
8623 	   int* ind;
8624 	   unsigned int nnonz;
8625 	   unsigned int ncols;
8626 	   unsigned int nrows;
8627 	   unsigned int i;
8628 	   unsigned int k;
8629 	
8630 	   assert(scip != NULL);
8631 	   assert(lp != NULL);
8632 	   assert(nvars > 0);
8633 	   assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8634 	
8635 	   SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8636 	
8637 	   /* create lpi to store the LP */
8638 	   SCIP_CALL( SCIPlpiCreate(lp, SCIPgetMessagehdlr(scip), "facet finding LP", SCIP_OBJSEN_MINIMIZE) );
8639 	
8640 	   nrows = (unsigned int)nvars + 1;
8641 	   ncols = POWEROFTWO((unsigned int)nvars);
8642 	   nnonz = (ncols * (nrows + 1)) / 2;
8643 	
8644 	   /* allocate necessary memory; set obj, lb, and ub to zero */
8645 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
8646 	   SCIP_CALL( SCIPallocClearBufferArray(scip, &lb, ncols) );
8647 	   SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8648 	   SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8649 	   SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8650 	   SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8651 	
8652 	   /* calculate nonzero entries in the LP */
8653 	   for( i = 0, k = 0; i < ncols; ++i )
8654 	   {
8655 	      int row;
8656 	      unsigned int a;
8657 	
8658 	      /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8659 	      ub[i] = SCIPlpiInfinity(*lp);
8660 	
8661 	      SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8662 	      beg[i] = (int)k;
8663 	      row = 0;
8664 	
8665 	      /* iterate through the bit representation of i */
8666 	      a = 1;
8667 	      while( a <= i )
8668 	      {
8669 	         if( (a & i) != 0 )
8670 	         {
8671 	            val[k] = 1.0;
8672 	            ind[k] = row;
8673 	
8674 	            SCIPdebugMsg(scip, " val[%d][%u] = 1 (position  %u)\n", row, i, k);
8675 	
8676 	            ++k;
8677 	         }
8678 	
8679 	         a <<= 1;
8680 	         ++row;
8681 	         assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8682 	         assert(POWEROFTWO(row) == a);
8683 	      }
8684 	
8685 	      /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8686 	      val[k] = 1.0;
8687 	      ind[k] = (int)nrows - 1;
8688 	      ++k;
8689 	      SCIPdebugMsg(scip, " val[%u][%u] = 1 (position  %u)\n", nrows - 1, i, k);
8690 	   }
8691 	   assert(k == nnonz);
8692 	
8693 	   /* load all data into LP interface
8694 	    * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8695 	    */
8696 	   assert(nrows <= ncols);
8697 	   SCIP_CALL( SCIPlpiLoadColLP(*lp, SCIP_OBJSEN_MINIMIZE,
8698 	      (int)ncols, obj, lb, ub, NULL,
8699 	      (int)nrows, lb, lb, NULL,
8700 	      (int)nnonz, beg, ind, val) );
8701 	
8702 	   /* for the last row, we can set the rhs to 1.0 already */
8703 	   ind[0] = (int)nrows - 1;
8704 	   val[0] = 1.0;
8705 	   SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8706 	
8707 	   /* free allocated memory */
8708 	   SCIPfreeBufferArray(scip, &ind);
8709 	   SCIPfreeBufferArray(scip, &val);
8710 	   SCIPfreeBufferArray(scip, &beg);
8711 	   SCIPfreeBufferArray(scip, &ub);
8712 	   SCIPfreeBufferArray(scip, &lb);
8713 	   SCIPfreeBufferArray(scip, &obj);
8714 	
8715 	   return SCIP_OKAY;
8716 	}
8717 	
8718 	/** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8719 	 * \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
8720 	 * set of vertices of the domain
8721 	 */
8722 	static
8723 	SCIP_Real computeVertexPolyhedralMaxFacetError(
8724 	   SCIP*                 scip,               /**< SCIP data structure */
8725 	   SCIP_Bool             overestimate,       /**< whether we check for an over or underestimator */
8726 	   SCIP_Real*            funvals,            /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8727 	   SCIP_Real*            box,                /**< box for which facet was computed, length: 2*nallvars */
8728 	   int                   nallvars,           /**< number of all variables */
8729 	   int                   nvars,              /**< number of unfixed variables */
8730 	   int*                  nonfixedpos,        /**< indices of unfixed variables, length: nvars */
8731 	   SCIP_Real*            facetcoefs,         /**< current facet candidate's coefficients, length: nallvars */
8732 	   SCIP_Real             facetconstant       /**< current facet candidate's constant, length: nallvars */
8733 	   )
8734 	{
8735 	   SCIP_Real maxerror;
8736 	   SCIP_Real facetval;
8737 	   SCIP_Real funval;
8738 	   SCIP_Real error;
8739 	   unsigned int i;
8740 	   unsigned int ncorners;
8741 	   unsigned int prev;
8742 	
8743 	   assert(scip != NULL);
8744 	   assert(funvals != NULL);
8745 	   assert(box != NULL);
8746 	   assert(nonfixedpos != NULL);
8747 	   assert(facetcoefs != NULL);
8748 	
8749 	   ncorners = POWEROFTWO(nvars);
8750 	   maxerror = 0.0;
8751 	
8752 	   /* check the origin (all variables at lower bound) */
8753 	   facetval = facetconstant;
8754 	   for( i = 0; i < (unsigned int) nallvars; ++i )
8755 	      facetval += facetcoefs[i] * box[2*i];
8756 	
8757 	   /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8758 	   funval = funvals[0];
8759 	   if( overestimate )
8760 	      error = funval - facetval;
8761 	   else
8762 	      error = facetval - funval;
8763 	
8764 	   /* update maximum error */
8765 	   maxerror = MAX(error, maxerror);
8766 	
8767 	   prev = 0;
8768 	   for( i = 1; i < ncorners; ++i )
8769 	   {
8770 	      unsigned int gray;
8771 	      unsigned int diff;
8772 	      unsigned int pos;
8773 	      int origpos;
8774 	
8775 	      gray = i ^ (i >> 1);
8776 	      diff = gray ^ prev;
8777 	
8778 	      /* compute position of unique 1 of diff */
8779 	      pos = 0;
8780 	      while( (diff >>= 1) != 0 )
8781 	         ++pos;
8782 	      assert(pos < (unsigned int)nvars);
8783 	
8784 	      origpos = nonfixedpos[pos];
8785 	
8786 	      if( gray > prev )
8787 	         facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8788 	      else
8789 	         facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8790 	
8791 	      /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8792 	      funval = funvals[gray];
8793 	      if( overestimate )
8794 	         error = funval - facetval;
8795 	      else
8796 	         error = facetval - funval;
8797 	
8798 	      /* update  maximum error */
8799 	      maxerror = MAX(error, maxerror);
8800 	
8801 	      prev = gray;
8802 	   }
8803 	
8804 	   SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8805 	
8806 	   return maxerror;
8807 	}
8808 	
8809 	/** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */  /*lint -e{715}*/
8810 	static
8811 	SCIP_RETCODE computeVertexPolyhedralFacetLP(
8812 	   SCIP*                 scip,               /**< SCIP data structure */
8813 	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
8814 	   SCIP_Bool             overestimate,       /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8815 	   SCIP_Real*            xstar,              /**< point to be separated */
8816 	   SCIP_Real*            box,                /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8817 	   int                   nallvars,           /**< half of the length of box */
8818 	   int*                  nonfixedpos,        /**< indices of nonfixed variables */
8819 	   SCIP_Real*            funvals,            /**< values of function in all corner points (w.r.t. nonfixed variables) */
8820 	   int                   nvars,              /**< number of nonfixed variables */
8821 	   SCIP_Real             targetvalue,        /**< target value: no need to compute facet if value in xstar would be worse than this value */
8822 	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
8823 	   SCIP_Real*            facetcoefs,         /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8824 	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
8825 	   )
8826 	{  /*lint --e{715}*/
8827 	   SCIP_CONSHDLRDATA* conshdlrdata;
8828 	   SCIP_LPI* lp;
8829 	   SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8830 	   int* inds;
8831 	   int ncols;
8832 	   int nrows;
8833 	   int i;
8834 	   SCIP_Real facetvalue;
8835 	   SCIP_Real mindomwidth;
8836 	   SCIP_RETCODE lpsolveretcode;
8837 	
8838 	   assert(scip != NULL);
8839 	   assert(conshdlr != NULL);
8840 	   assert(xstar != NULL);
8841 	   assert(box != NULL);
8842 	   assert(nonfixedpos != NULL);
8843 	   assert(funvals != NULL);
8844 	   assert(nvars >= 0);
8845 	   assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8846 	   assert(success != NULL);
8847 	   assert(facetcoefs != NULL);
8848 	   assert(facetconstant != NULL);
8849 	
8850 	   *success = FALSE;
8851 	
8852 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
8853 	   assert(conshdlrdata != NULL);
8854 	
8855 	   if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8856 	   {
8857 	      SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8858 	   }
8859 	
8860 	   /* construct an LP for this size, if not having one already */
8861 	   if( conshdlrdata->vp_lp[nvars] == NULL )
8862 	   {
8863 	      SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8864 	   }
8865 	   lp = conshdlrdata->vp_lp[nvars];
8866 	   assert(lp != NULL);
8867 	
8868 	   /* get number of cols and rows of separation lp */
8869 	   SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8870 	   SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8871 	
8872 	   /* number of columns should equal the number of corners = 2^nvars */
8873 	   assert(ncols == (int)POWEROFTWO(nvars));
8874 	
8875 	   /* allocate necessary memory */
8876 	   SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8877 	   SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8878 	
8879 	   /*
8880 	    * set up the described LP on the transformed space
8881 	    */
8882 	
8883 	   for( i = 0; i < ncols; ++i )
8884 	      inds[i] = i;
8885 	
8886 	   /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
8887 	   mindomwidth = 2*SCIPinfinity(scip);
8888 	   for( i = 0; i < nrows-1; ++i )
8889 	   {
8890 	      SCIP_Real solval;
8891 	      SCIP_Real lb;
8892 	      SCIP_Real ub;
8893 	      int varpos;
8894 	
8895 	      assert(i < nvars);
8896 	
8897 	      varpos = nonfixedpos[i];
8898 	      lb = box[2 * varpos];
8899 	      ub = box[2 * varpos + 1];
8900 	      solval = xstar[varpos];
8901 	
8902 	      if( ub - lb < mindomwidth )
8903 	         mindomwidth = ub - lb;
8904 	
8905 	      /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
8906 	      if( solval <= lb )
8907 	         aux[i] = 0.0;
8908 	      else if( solval >= ub )
8909 	         aux[i] = 1.0;
8910 	      else
8911 	         aux[i] = (solval - lb) / (ub - lb);
8912 	
8913 	      /* perturb point to hopefully obtain a facet of the convex envelope */
8914 	      if( conshdlrdata->vp_maxperturb > 0.0 )
8915 	      {
8916 	         assert(conshdlrdata->vp_randnumgen != NULL);
8917 	
8918 	         if( aux[i] == 1.0 )
8919 	            aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
8920 	         else if( aux[i] == 0.0 )
8921 	            aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
8922 	         else
8923 	         {
8924 	            SCIP_Real perturbation;
8925 	
8926 	            perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
8927 	            perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
8928 	            aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
8929 	         }
8930 	         assert(0.0 < aux[i] && aux[i] < 1.0);
8931 	      }
8932 	
8933 	      SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
8934 	   }
8935 	
8936 	   /* update LP */
8937 	   SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
8938 	   SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
8939 	   SCIP_CALL( SCIPlpiChgObjsen(lp, overestimate ? SCIP_OBJSEN_MAXIMIZE : SCIP_OBJSEN_MINIMIZE) );
8940 	
8941 	   /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
8942 	   if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
8943 	   {
8944 	      SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
8945 	   }
8946 	   /* set an iteration limit so we do not run forever */
8947 	   SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPITLIM, 100*ncols) );
8948 	   /* 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 */
8949 	   SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_FEASTOL, SCIPfeastol(scip)) );
8950 	   /* since we work with the dual of the LP, dual feastol determines validity of the facet
8951 	    * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
8952 	    * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
8953 	    */
8954 	   SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, MIN(SCIPfeastol(scip), MAX(SCIPepsilon(scip), mindomwidth * SCIPfeastol(scip)))) );
8955 	
8956 	#ifdef SCIP_DEBUG
8957 	   SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPINFO, 1) );
8958 	#endif
8959 	
8960 	   /*
8961 	    * solve the LP and store the resulting facet for the transformed space
8962 	    */
8963 	   if( conshdlrdata->vp_dualsimplex )
8964 	   {
8965 	      lpsolveretcode = SCIPlpiSolveDual(lp);
8966 	   }
8967 	   else
8968 	   {
8969 	      lpsolveretcode = SCIPlpiSolvePrimal(lp);
8970 	   }
8971 	   if( lpsolveretcode == SCIP_LPERROR )
8972 	   {
8973 	      SCIPdebugMsg(scip, "LP error, aborting.\n");
8974 	      goto CLEANUP;
8975 	   }
8976 	   SCIP_CALL( lpsolveretcode );
8977 	
8978 	   /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
8979 	   if( !SCIPlpiIsDualFeasible(lp) )
8980 	   {
8981 	      SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
8982 	      goto CLEANUP;
8983 	   }
8984 	
8985 	   /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
8986 	    * columns than needed, in particular, \bar \beta is the last dual multiplier
8987 	    */
8988 	   SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
8989 	
8990 	   for( i = 0; i < nvars; ++i )
8991 	      facetcoefs[nonfixedpos[i]] = aux[i];
8992 	   /* last dual multiplier is the constant */
8993 	   *facetconstant = aux[nrows - 1];
8994 	
8995 	#ifdef SCIP_DEBUG
8996 	   SCIPdebugMsg(scip, "facet for the transformed problem: ");
8997 	   for( i = 0; i < nallvars; ++i )
8998 	   {
8999 	      SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9000 	   }
9001 	   SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9002 	#endif
9003 	
9004 	   /*
9005 	    * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9006 	    */
9007 	
9008 	   SCIPdebugMsg(scip, "facet in orig. space: ");
9009 	
9010 	   facetvalue = 0.0;
9011 	   for( i = 0; i < nvars; ++i )
9012 	   {
9013 	      SCIP_Real lb;
9014 	      SCIP_Real ub;
9015 	      int varpos;
9016 	
9017 	      varpos = nonfixedpos[i];
9018 	      lb = box[2 * varpos];
9019 	      ub = box[2 * varpos + 1];
9020 	      assert(!SCIPisEQ(scip, lb, ub));
9021 	
9022 	      /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9023 	      facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9024 	
9025 	      /* beta = beta_bar - sum_i alpha_i * lb_i */
9026 	      *facetconstant -= facetcoefs[varpos] * lb;
9027 	
9028 	      /* evaluate */
9029 	      facetvalue += facetcoefs[varpos] * xstar[varpos];
9030 	
9031 	      SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9032 	   }
9033 	   SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9034 	
9035 	   /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9036 	   facetvalue += *facetconstant;
9037 	
9038 	   SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9039 	
9040 	    /* if overestimate, then we want facetvalue < targetvalue
9041 	    * if underestimate, then we want facetvalue > targetvalue
9042 	    * if none holds, give up
9043 	    * so maybe here we should check against the minimal violation
9044 	    */
9045 	   if( overestimate == (facetvalue > targetvalue) )
9046 	   {
9047 	      SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9048 	      goto CLEANUP;
9049 	   }
9050 	
9051 	   /* if we made it until here, then we have a nice facet */
9052 	   *success = TRUE;
9053 	
9054 	CLEANUP:
9055 	   /* free allocated memory */
9056 	   SCIPfreeBufferArray(scip, &inds);
9057 	   SCIPfreeBufferArray(scip, &aux);
9058 	
9059 	   return SCIP_OKAY;
9060 	}
9061 	
9062 	/** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
9063 	 *
9064 	 * In other words, compute the line that passes through two given points.
9065 	 */
9066 	static
9067 	SCIP_RETCODE computeVertexPolyhedralFacetUnivariate(
9068 	   SCIP*                 scip,               /**< SCIP data structure */
9069 	   SCIP_Real             left,               /**< left coordinate */
9070 	   SCIP_Real             right,              /**< right coordinate */
9071 	   SCIP_Real             funleft,            /**< value of function in left coordinate */
9072 	   SCIP_Real             funright,           /**< value of function in right coordinate */
9073 	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
9074 	   SCIP_Real*            facetcoef,          /**< buffer to store coefficient of facet defining inequality */
9075 	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
9076 	   )
9077 	{
9078 	   assert(scip != NULL);
9079 	   assert(SCIPisLE(scip, left, right));
9080 	   assert(!SCIPisInfinity(scip, -left));
9081 	   assert(!SCIPisInfinity(scip, right));
9082 	   assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9083 	   assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9084 	   assert(success != NULL);
9085 	   assert(facetcoef != NULL);
9086 	   assert(facetconstant != NULL);
9087 	
9088 	   *facetcoef = (funright - funleft) / (right - left);
9089 	   *facetconstant = funleft - *facetcoef * left;
9090 	
9091 	   *success = TRUE;
9092 	
9093 	   return SCIP_OKAY;
9094 	}
9095 	
9096 	/** given three points, constructs coefficient of equation for hyperplane generated by these three points
9097 	 *
9098 	 * Three points a, b, and c are given.
9099 	 * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9100 	 * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9101 	 */
9102 	static
9103 	SCIP_RETCODE computeHyperplaneThreePoints(
9104 	   SCIP*                 scip,               /**< SCIP data structure */
9105 	   SCIP_Real             a1,                 /**< first coordinate of a */
9106 	   SCIP_Real             a2,                 /**< second coordinate of a */
9107 	   SCIP_Real             a3,                 /**< third coordinate of a */
9108 	   SCIP_Real             b1,                 /**< first coordinate of b */
9109 	   SCIP_Real             b2,                 /**< second coordinate of b */
9110 	   SCIP_Real             b3,                 /**< third coordinate of b */
9111 	   SCIP_Real             c1,                 /**< first coordinate of c */
9112 	   SCIP_Real             c2,                 /**< second coordinate of c */
9113 	   SCIP_Real             c3,                 /**< third coordinate of c */
9114 	   SCIP_Real*            alpha,              /**< coefficient of first coordinate */
9115 	   SCIP_Real*            beta,               /**< coefficient of second coordinate */
9116 	   SCIP_Real*            gamma_,             /**< coefficient of third coordinate */
9117 	   SCIP_Real*            delta               /**< constant right-hand side */
9118 	   )
9119 	{
9120 	   assert(scip != NULL);
9121 	   assert(alpha != NULL);
9122 	   assert(beta  != NULL);
9123 	   assert(gamma_ != NULL);
9124 	   assert(delta != NULL);
9125 	
9126 	   *alpha  = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9127 	   *beta   = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9128 	   *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9129 	   *delta  = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9130 	
9131 	   /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9132 	
9133 	   if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9134 	      SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9135 	      SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9136 	   {
9137 	      SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9138 	      *delta  = 0.0;
9139 	      *alpha  = 0.0;
9140 	      *beta   = 0.0;
9141 	      *gamma_ = 0.0;
9142 	      return SCIP_OKAY;
9143 	   }
9144 	
9145 	   /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9146 	   if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9147 	      !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9148 	      !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9149 	   {
9150 	      SCIP_Real m[9];
9151 	      SCIP_Real rhs[3];
9152 	      SCIP_Real x[3];
9153 	      SCIP_Bool success;
9154 	
9155 	      /*
9156 	      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));
9157 	      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));
9158 	      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));
9159 	      */
9160 	
9161 	      /* initialize matrix column-wise */
9162 	      m[0] = a1;
9163 	      m[1] = b1;
9164 	      m[2] = c1;
9165 	      m[3] = a2;
9166 	      m[4] = b2;
9167 	      m[5] = c2;
9168 	      m[6] = a3;
9169 	      m[7] = b3;
9170 	      m[8] = c3;
9171 	
9172 	      rhs[0] = 1.0;
9173 	      rhs[1] = 1.0;
9174 	      rhs[2] = 1.0;
9175 	
9176 	      SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9177 	
9178 	      /* solve the linear problem */
9179 	      SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
9180 	
9181 	      *delta  = rhs[0];
9182 	      *alpha  = x[0];
9183 	      *beta   = x[1];
9184 	      *gamma_ = x[2];
9185 	
9186 	      /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9187 	       * not add a cut to SCIP and that all assertions are trivially fulfilled
9188 	       */
9189 	      if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9190 	         !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9191 	         !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9192 	      {
9193 	         SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9194 	         *delta  = 0.0;
9195 	         *alpha  = 0.0;
9196 	         *beta   = 0.0;
9197 	         *gamma_ = 0.0;
9198 	      }
9199 	   }
9200 	
9201 	   if( *gamma_ < 0.0 )
9202 	   {
9203 	      *alpha  = -*alpha;
9204 	      *beta   = -*beta;
9205 	      *gamma_ = -*gamma_;
9206 	      *delta  = -*delta;
9207 	   }
9208 	
9209 	   return SCIP_OKAY;
9210 	}
9211 	
9212 	/** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9213 	static
9214 	SCIP_RETCODE computeVertexPolyhedralFacetBivariate(
9215 	   SCIP*                 scip,               /**< SCIP data structure */
9216 	   SCIP_Bool             overestimate,       /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9217 	   SCIP_Real             p1[2],              /**< first vertex of box */
9218 	   SCIP_Real             p2[2],              /**< second vertex of box */
9219 	   SCIP_Real             p3[2],              /**< third vertex of box */
9220 	   SCIP_Real             p4[2],              /**< forth vertex of box */
9221 	   SCIP_Real             p1val,              /**< value in p1 */
9222 	   SCIP_Real             p2val,              /**< value in p2 */
9223 	   SCIP_Real             p3val,              /**< value in p3 */
9224 	   SCIP_Real             p4val,              /**< value in p4 */
9225 	   SCIP_Real             xstar[2],           /**< point to be separated */
9226 	   SCIP_Real             targetvalue,        /**< target value: no need to compute facet if value in xstar would be worse than this value */
9227 	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
9228 	   SCIP_Real*            facetcoefs,         /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9229 	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
9230 	   )
9231 	{
9232 	   SCIP_Real alpha, beta, gamma_, delta;
9233 	   SCIP_Real xstarval, candxstarval = 0.0;
9234 	   int leaveout;
9235 	
9236 	   assert(scip != NULL);
9237 	   assert(success != NULL);
9238 	   assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9239 	   assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9240 	   assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9241 	   assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9242 	   assert(facetcoefs != NULL);
9243 	   assert(facetconstant != NULL);
9244 	
9245 	   *success = FALSE;
9246 	
9247 	   /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9248 	   if( !overestimate )
9249 	   {
9250 	      p1val = -p1val;
9251 	      p2val = -p2val;
9252 	      p3val = -p3val;
9253 	      p4val = -p4val;
9254 	      targetvalue = -targetvalue;
9255 	   }
9256 	
9257 	   SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9258 	   SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9259 	   SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9260 	   SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9261 	
9262 	   /* Compute coefficients alpha, beta, gamma (>0), delta such that
9263 	    *   alpha*x + beta*y + gamma*z = delta
9264 	    * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9265 	    * the fourth corner point lies below this hyperplane.
9266 	    * 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.,
9267 	    *    alpha*x + beta*y - delta <= -gamma * f(x,y),
9268 	    * or, equivalently,
9269 	    *   -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9270 	    */
9271 	   for( leaveout = 1; leaveout <= 4; ++leaveout )
9272 	   {
9273 	      switch( leaveout)
9274 	      {
9275 	         case 1 :
9276 	            /* get hyperplane through p2, p3, p4 */
9277 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9278 	               &alpha, &beta, &gamma_, &delta) );
9279 	            /* if not underestimating in p1, then go to next candidate */
9280 	            if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9281 	               continue;
9282 	            break;
9283 	
9284 	         case 2 :
9285 	            /* get hyperplane through p1, p3, p4 */
9286 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9287 	               &alpha, &beta, &gamma_, &delta) );
9288 	            /* if not underestimating in p2, then go to next candidate */
9289 	            if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9290 	               continue;
9291 	            break;
9292 	
9293 	         case 3 :
9294 	            /* get hyperplane through p1, p2, p4 */
9295 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9296 	               &alpha, &beta, &gamma_, &delta) );
9297 	            /* if not underestimating in p3, then go to next candidate */
9298 	            if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9299 	               continue;
9300 	            break;
9301 	
9302 	         case 4 :
9303 	            /* get hyperplane through p1, p2, p3 */
9304 	            SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9305 	               &alpha, &beta, &gamma_, &delta) );
9306 	            /* if not underestimating in p4, then stop */
9307 	            if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9308 	               continue;
9309 	            break;
9310 	
9311 	         default: /* only for lint */
9312 	            alpha = SCIP_INVALID;
9313 	            beta = SCIP_INVALID;
9314 	            gamma_ =  SCIP_INVALID;
9315 	            delta = SCIP_INVALID;
9316 	            break;
9317 	      }
9318 	
9319 	      /* check if bad luck: should not happen if numerics are fine */
9320 	      if( SCIPisZero(scip, gamma_) )
9321 	         continue;
9322 	      assert(!SCIPisNegative(scip, gamma_));
9323 	
9324 	      /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9325 	      if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9326 	         ( !SCIPisZero(scip, beta)  && SCIPisZero(scip, beta/gamma_)) )
9327 	         continue;
9328 	
9329 	      SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9330 	
9331 	      /* value of hyperplane candidate in xstar */
9332 	      xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9333 	
9334 	      /* if reaching target and first or better than previous candidate, then update */
9335 	      if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9336 	      {
9337 	         /* flip hyperplane */
9338 	         if( !overestimate )
9339 	            gamma_ = -gamma_;
9340 	
9341 	         facetcoefs[0] = -alpha/gamma_;
9342 	         facetcoefs[1] = -beta/gamma_;
9343 	         *facetconstant = delta/gamma_;
9344 	
9345 	         *success = TRUE;
9346 	         candxstarval = xstarval;
9347 	      }
9348 	   }
9349 	
9350 	   return SCIP_OKAY;
9351 	}
9352 	
9353 	/** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
9354 	 *  graph yet) in an array
9355 	 */
9356 	static
9357 	SCIP_RETCODE ensureOpenArraySizeSymdetect(
9358 	   SCIP*                 scip,               /**< SCIP pointer */
9359 	   int**                 openidx,            /**< address of openidx array */
9360 	   int                   nelems,             /**< number of elements that need to be stored */
9361 	   int*                  maxnelems           /**< pointer to store maximum number that can be stored */
9362 	   )
9363 	{
9364 	   assert(scip != NULL);
9365 	   assert(openidx != NULL);
9366 	   assert(maxnelems != NULL);
9367 	
9368 	   if( nelems > *maxnelems )
9369 	   {
9370 	      int newsize;
9371 	
9372 	      newsize = SCIPcalcMemGrowSize(scip, nelems);
9373 	      assert(newsize >= nelems);
9374 	
9375 	      SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
9376 	
9377 	      *maxnelems = newsize;
9378 	   }
9379 	
9380 	   return SCIP_OKAY;
9381 	}
9382 	
9383 	/** ensures that we can store information about local variables in an array */
9384 	static
9385 	SCIP_RETCODE ensureLocVarsArraySize(
9386 	   SCIP*                 scip,               /**< SCIP pointer */
9387 	   SCIP_VAR***           vars,               /**< address of variable array */
9388 	   SCIP_Real**           vals,               /**< address of value array */
9389 	   int                   nelems,             /**< number of elements that need to be stored */
9390 	   int*                  maxnelems           /**< pointer to store maximum number that can be stored */
9391 	   )
9392 	{
9393 	   assert(scip != NULL);
9394 	   assert(vars != NULL);
9395 	   assert(vals != NULL);
9396 	   assert(maxnelems != NULL);
9397 	
9398 	   if( nelems > *maxnelems )
9399 	   {
9400 	      int newsize;
9401 	
9402 	      newsize = SCIPcalcMemGrowSize(scip, nelems);
9403 	      assert(newsize > *maxnelems);
9404 	
9405 	      SCIP_CALL( SCIPreallocBufferArray(scip, vars, newsize) );
9406 	      SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
9407 	
9408 	      *maxnelems = newsize;
9409 	   }
9410 	
9411 	   return SCIP_OKAY;
9412 	}
9413 	
9414 	/** tries to add gadget for finding signed permutations of bilinear products
9415 	 *
9416 	 *  If a product has exactly two children being variables, negating both simultanteoulsy
9417 	 *  is a signed permutation.
9418 	 */
9419 	static
9420 	SCIP_RETCODE tryAddGadgetBilinearProductSignedPerm(
9421 	   SCIP*                 scip,               /**< SCIP pointer */
9422 	   SCIP_EXPR*            expr,               /**< product expression for which gadget is tried to be added */
9423 	   SCIP_CONS*            cons,               /**< constraint containing product expression */
9424 	   SYM_GRAPH*            graph,              /**< symmetry detection graph to be extended by gadget */
9425 	   int                   parentidx,          /**< index of parent node in symmetry detection graph for gadget */
9426 	   SCIP_Bool             hasparentcoef,      /**< whether the parent gives a coefficient to the expression */
9427 	   SCIP_Real             parentcoef,         /**< the parent coefficient (if it exists) */
9428 	   SCIP_VAR***           consvars,           /**< pointer to allocated array to store temporary variables */
9429 	   SCIP_Real**           consvals,           /**< pointer to allocated arrat to store temporary values */
9430 	   int*                  maxnconsvars,       /**< pointer to maximum number consvars/consvals can hold */
9431 	   SCIP_HASHSET*         handledexprs,       /**< hashset to store handled expressions */
9432 	   SCIP_Bool*            success             /**< pointer to store whether gadget could be added successfully */
9433 	   )
9434 	{
9435 	   SYM_EXPRDATA* symdata;
9436 	   SCIP_EXPR** children;
9437 	   SCIP_VAR* var1 = NULL;
9438 	   SCIP_VAR* var2 = NULL;
9439 	   SCIP_Real val1 = 0.0;
9440 	   SCIP_Real val2 = 0.0;
9441 	   SCIP_Real coef;
9442 	   SCIP_Real prodval;
9443 	   SCIP_Real constant;
9444 	   int nlocvars;
9445 	   int optype;
9446 	   int nchildren;
9447 	   int prodidx;
9448 	   int coefidx1;
9449 	   int coefidx2;
9450 	   int childidx;
9451 	
9452 	   assert(scip != NULL);
9453 	   assert(expr != NULL);
9454 	   assert(SCIPisExprProduct(scip, expr));
9455 	   assert(graph != NULL);
9456 	   assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
9457 	   assert(consvars != NULL);
9458 	   assert(consvals != NULL);
9459 	   assert(maxnconsvars != NULL);
9460 	   assert(*maxnconsvars > 0);
9461 	   assert(handledexprs != NULL);
9462 	   assert(success != NULL);
9463 	
9464 	   *success = FALSE;
9465 	
9466 	   /* we require exactly two children being variables */
9467 	   nchildren = SCIPexprGetNChildren(expr);
9468 	   if( nchildren != 2 )
9469 	      return SCIP_OKAY;
9470 	
9471 	   children = SCIPexprGetChildren(expr);
9472 	   if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
9473 	      return SCIP_OKAY;
9474 	
9475 	   /* check whether each child is not multi-aggregated and is not shifted */
9476 	   SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
9477 	
9478 	   for( childidx = 0; childidx < 2; ++childidx )
9479 	   {
9480 	      (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
9481 	      (*consvals)[0] = 1.0;
9482 	      nlocvars = 1;
9483 	      constant = 0.0;
9484 	
9485 	      SCIP_CALL( SCIPgetActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
9486 	            &constant, SCIPconsIsTransformed(cons)) );
9487 	
9488 	      if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9489 	         return SCIP_OKAY;
9490 	
9491 	      if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
9492 	            != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
9493 	         return SCIP_OKAY;
9494 	
9495 	      /* store information about variables */
9496 	      if( childidx == 0 )
9497 	      {
9498 	         var1 = (*consvars)[0];
9499 	         val1 = (*consvals)[0];
9500 	      }
9501 	      else
9502 	      {
9503 	         var2 = (*consvars)[0];
9504 	         val2 = (*consvals)[0];
9505 	      }
9506 	   }
9507 	   assert(var1 != NULL);
9508 	   assert(var2 != NULL);
9509 	
9510 	   /* store the we handle the children */
9511 	   SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
9512 	   SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
9513 	
9514 	   SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
9515 	   assert(symdata != NULL);
9516 	   assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9517 	
9518 	   coef = SCIPgetSymExprdataConstants(symdata)[0];
9519 	
9520 	   SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
9521 	
9522 	   /* add gadget modeling the product
9523 	    *
9524 	    * Since the constants are 0, each variable is centered at the origin, which leads to
9525 	    * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
9526 	    * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
9527 	    * negate both variables simulataneously.
9528 	    */
9529 	   SCIP_CALL( SCIPgetSymOpNodeType(scip, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), &optype) );
9530 	   SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
9531 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
9532 	
9533 	   prodval = coef * val1 * val2;
9534 	
9535 	   /* introduce nodes for the product value and its negation; since flipping both variables
9536 	    * simultaneously is a signed symmetry, assign both nodes the same value
9537 	    */
9538 	   SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
9539 	   SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
9540 	
9541 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
9542 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
9543 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
9544 	
9545 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9546 	         SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9547 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9548 	         SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9549 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9550 	         SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9551 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9552 	         SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9553 	
9554 	   *success = TRUE;
9555 	
9556 	   return SCIP_OKAY;
9557 	}
9558 	
9559 	/** returns whether an operator is even and, if yes, stores data about operator */
9560 	static
9561 	SCIP_Bool isEvenOperator(
9562 	   SCIP*                 scip,               /**< SCIP pointer */
9563 	   SCIP_EXPR*            expr,               /**< expression corresponding to operator */
9564 	   SCIP_Bool*            hasvalue,           /**< pointer to store whether even operator has a value
9565 	                                              *   needed for symmetry computation */
9566 	   SCIP_Real*            value               /**< pointer to store value for symmetry computation */
9567 	   )
9568 	{
9569 	   SYM_EXPRDATA* symdata;
9570 	
9571 	   assert(scip != NULL);
9572 	   assert(expr != NULL);
9573 	   assert(hasvalue != NULL);
9574 	   assert(value != NULL);
9575 	
9576 	   /* check for different operators known to be even */
9577 	   if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
9578 	   {
9579 	      /* get remaining information needed for symmetry detection */
9580 	      if( SCIPisExprSignpower(scip, expr) )
9581 	      {
9582 	         SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9583 	         assert(symdata != NULL);
9584 	         assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9585 	
9586 	         *value = SCIPgetSymExprdataConstants(symdata)[0];
9587 	         *hasvalue = !SCIPisEQ(scip, *value, 1.0);
9588 	
9589 	         SCIP_CALL_ABORT( SCIPfreeSymDataExpr(scip, &symdata) );
9590 	      }
9591 	      else
9592 	      {
9593 	         assert(SCIPisExprCos(scip, expr));
9594 	         *hasvalue = FALSE;
9595 	      }
9596 	
9597 	      return TRUE;
9598 	   }
9599 	   else if( SCIPisExprPower(scip, expr) )
9600 	   {
9601 	      SCIP_Real exponent;
9602 	      int safeexponent;
9603 	
9604 	      /* only consider expressions corresponding to an even power */
9605 	      SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9606 	      assert(symdata != NULL);
9607 	      assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9608 	
9609 	      exponent = SCIPgetSymExprdataConstants(symdata)[0];
9610 	      SCIP_CALL_ABORT( SCIPfreeSymDataExpr(scip, &symdata) );
9611 	
9612 	      /* check whether the exponent is an even integer */
9613 	      if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
9614 	         return FALSE;
9615 	
9616 	      /* deal with numerics */
9617 	      safeexponent = (int) (exponent + 0.5);
9618 	      if( safeexponent % 2 != 0 )
9619 	         return FALSE;
9620 	
9621 	      *hasvalue = TRUE;
9622 	      *value = exponent;
9623 	
9624 	      return TRUE;
9625 	   }
9626 	   else if( SCIPisExprAbs(scip, expr) )
9627 	   {
9628 	      *hasvalue = FALSE;
9629 	
9630 	      return TRUE;
9631 	   }
9632 	
9633 	   return FALSE;
9634 	}
9635 	
9636 	/** returns whether a variable is centered at 0 */
9637 	static
9638 	SCIP_Bool varIsCenteredAt0(
9639 	   SCIP*                 scip,               /**< SCIP pointer */
9640 	   SCIP_VAR*             var                 /**< variable to be checked */
9641 	   )
9642 	{
9643 	   assert(scip != NULL);
9644 	   assert(var != NULL);
9645 	
9646 	   if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) != SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var))) )
9647 	      return FALSE;
9648 	
9649 	   if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
9650 	      return TRUE;
9651 	
9652 	   if( SCIPisEQ(scip, SCIPvarGetUbGlobal(var), -SCIPvarGetLbGlobal(var)) )
9653 	      return TRUE;
9654 	
9655 	   return FALSE;
9656 	}
9657 	
9658 	/** tries to add gadget for finding signed permutation of even univariate operators with variable child */
9659 	static
9660 	SCIP_RETCODE tryAddGadgetEvenOperatorVariable(
9661 	   SCIP*                 scip,               /**< SCIP pointer */
9662 	   SCIP_EXPR*            evenopexpr,         /**< even operator expression for which gadget is tried to be added */
9663 	   SCIP_EXPR*            child,              /**< child expression of evenopexpr */
9664 	   SCIP_CONS*            cons,               /**< constraint containing expression */
9665 	   SYM_GRAPH*            graph,              /**< symmetry detection graph to be extended by gadget */
9666 	   int                   parentidx,          /**< index of parent node in symmetry detection graph for gadget */
9667 	   SCIP_Bool             hasparentcoef,      /**< whether the parent gives a coefficient to the expression */
9668 	   SCIP_Real             parentcoef,         /**< the parent coefficient (if it exists) */
9669 	   SCIP_Bool             hassymval,          /**< whether evenopexpr has a value needed for symmetry detection */
9670 	   SCIP_Real             symval,             /**< value needed for symmetry detection (if hassymval is TRUE) */
9671 	   SCIP_VAR***           consvars,           /**< pointer to allocated array to store temporary variables */
9672 	   SCIP_Real**           consvals,           /**< pointer to allocated arrat to store temporary values */
9673 	   int*                  maxnconsvars,       /**< pointer to maximum number consvars/consvals can hold */
9674 	   SCIP_Bool*            success             /**< pointer to store whether gadget could be added successfully */
9675 	   )
9676 	{
9677 	   SCIP_VAR* var;
9678 	   SCIP_Real constant;
9679 	   SCIP_Real edgeweight;
9680 	   int nlocvars;
9681 	   int nodeidx;
9682 	   int optype;
9683 	   int thisopidx;
9684 	
9685 	   assert(scip != NULL);
9686 	   assert(evenopexpr != NULL);
9687 	   assert(child != NULL);
9688 	   assert(SCIPisExprVar(scip, child));
9689 	   assert(cons != NULL);
9690 	   assert(graph != NULL);
9691 	   assert(parentidx >= 0);
9692 	   assert(consvars != NULL);
9693 	   assert(consvals != NULL);
9694 	   assert(maxnconsvars != NULL);
9695 	   assert(success != NULL);
9696 	
9697 	   *success = FALSE;
9698 	
9699 	   /* check whether child variable is (multi-)aggregated */
9700 	   var = SCIPgetVarExprVar(child);
9701 	   (*consvars)[0] = var;
9702 	   (*consvals)[0] = 1.0;
9703 	   constant = 0.0;
9704 	   nlocvars = 1;
9705 	
9706 	   SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
9707 	   SCIP_CALL( SCIPgetActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
9708 	         SCIPconsIsTransformed(cons)) );
9709 	
9710 	   /* skip multi-aggregated variables or variables with domain not centered at 0 */
9711 	   if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9712 	      return SCIP_OKAY;
9713 	
9714 	   if( !varIsCenteredAt0(scip, var) )
9715 	      return SCIP_OKAY;
9716 	
9717 	   /* store partial information for gadget */
9718 	   var = (*consvars)[0];
9719 	   edgeweight = (*consvals)[0];
9720 	
9721 	   /* add gadget to graph for even univariate expression */
9722 	   *success = TRUE;
9723 	
9724 	   SCIP_CALL( SCIPgetSymOpNodeType(scip, SCIPexprhdlrGetName(SCIPexprGetHdlr(evenopexpr)), &optype) );
9725 	
9726 	   SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
9727 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
9728 	
9729 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
9730 	         TRUE, edgeweight) );
9731 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var),
9732 	         TRUE, edgeweight) );
9733 	
9734 	   if( hassymval )
9735 	   {
9736 	      SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
9737 	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
9738 	   }
9739 	
9740 	   return SCIP_OKAY;
9741 	}
9742 	
9743 	/** tries to add gadget for finding signed permutation of even univariate operators with sum child */
9744 	static
9745 	SCIP_RETCODE tryAddGadgetEvenOperatorSum(
9746 	   SCIP*                 scip,               /**< SCIP pointer */
9747 	   SCIP_EXPR*            evenopexpr,         /**< even operator expression for which gadget is tried to be added */
9748 	   SCIP_EXPR*            child,              /**< child expression of evenopexpr */
9749 	   SCIP_CONS*            cons,               /**< constraint containing expression */
9750 	   SYM_GRAPH*            graph,              /**< symmetry detection graph to be extended by gadget */
9751 	   int                   parentidx,          /**< index of parent node in symmetry detection graph for gadget */
9752 	   SCIP_Bool             hasparentcoef,      /**< whether the parent gives a coefficient to the expression */
9753 	   SCIP_Real             parentcoef,         /**< the parent coefficient (if it exists) */
9754 	   SCIP_Bool             hassymval,          /**< whether evenopexpr has a value needed for symmetry detection */
9755 	   SCIP_Real             symval,             /**< value needed for symmetry detection (if hassymval is TRUE) */
9756 	   SCIP_VAR***           consvars,           /**< pointer to allocated array to store temporary variables */
9757 	   SCIP_Real**           consvals,           /**< pointer to allocated arrat to store temporary values */
9758 	   int*                  maxnconsvars,       /**< pointer to maximum number consvars/consvals can hold */
9759 	   SCIP_HASHSET*         handledexprs,       /**< hashset to store handled expressions */
9760 	   SCIP_Bool*            success             /**< pointer to store whether gadget could be added successfully */
9761 	   )
9762 	{
9763 	   SCIP_VAR* var;
9764 	   SCIP_Real constant;
9765 	   SCIP_Real weight;
9766 	   int nlocvars;
9767 	   int nodeidx;
9768 	   int optype;
9769 	   int thisopidx;
9770 	   int i;
9771 	
9772 	   assert(scip != NULL);
9773 	   assert(evenopexpr != NULL);
9774 	   assert(child != NULL);
9775 	   assert(SCIPisExprSum(scip, child));
9776 	   assert(cons != NULL);
9777 	   assert(graph != NULL);
9778 	   assert(parentidx >= 0);
9779 	   assert(consvars != NULL);
9780 	   assert(consvals != NULL);
9781 	   assert(maxnconsvars != NULL);
9782 	   assert(handledexprs != NULL);
9783 	   assert(success != NULL);
9784 	
9785 	   *success = FALSE;
9786 	
9787 	   /* check whether child variable is (multi-)aggregated and whether all children are variables */
9788 	   nlocvars = SCIPexprGetNChildren(child);
9789 	
9790 	   SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
9791 	
9792 	   for( i = 0; i < nlocvars; ++i)
9793 	   {
9794 	      if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
9795 	      {
9796 	         (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
9797 	         (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
9798 	      }
9799 	      else
9800 	         return SCIP_OKAY;
9801 	   }
9802 	   constant = SCIPgetConstantExprSum(child);
9803 	
9804 	   SCIP_CALL( SCIPgetActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
9805 	         SCIPconsIsTransformed(cons)) );
9806 	
9807 	   /* we can only handle the case without constant and two variables with domain centered at origin */
9808 	   if( nlocvars > 2 || !SCIPisZero(scip, constant) )
9809 	      return SCIP_OKAY;
9810 	   assert(nlocvars > 0);
9811 	
9812 	   var = (*consvars)[0];
9813 	   if( !varIsCenteredAt0(scip, var) )
9814 	      return SCIP_OKAY;
9815 	
9816 	   if( nlocvars == 2 )
9817 	   {
9818 	      var = (*consvars)[1];
9819 	      if( !varIsCenteredAt0(scip, var) )
9820 	         return SCIP_OKAY;
9821 	   }
9822 	
9823 	   /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
9824 	   *success = TRUE;
9825 	   for( i = 0; i < SCIPexprGetNChildren(child); ++i )
9826 	   {
9827 	      SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
9828 	   }
9829 	
9830 	   SCIP_CALL( SCIPgetSymOpNodeType(scip, SCIPexprhdlrGetName(SCIPexprGetHdlr(evenopexpr)), &optype) );
9831 	
9832 	   SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
9833 	   SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
9834 	
9835 	   if( hassymval )
9836 	   {
9837 	      SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
9838 	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
9839 	   }
9840 	
9841 	   if( nlocvars == 1 )
9842 	   {
9843 	      var = (*consvars)[0];
9844 	      weight = (*consvals)[0];
9845 	
9846 	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
9847 	            TRUE, weight) );
9848 	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var),
9849 	            TRUE, weight) );
9850 	   }
9851 	   else
9852 	   {
9853 	      int dummyidx1;
9854 	      int dummyidx2;
9855 	
9856 	      /* add dummy nodes for gadget */
9857 	      SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
9858 	      SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
9859 	
9860 	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
9861 	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
9862 	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
9863 	
9864 	      /* connect dummy nodes with variables */
9865 	      for( i = 0; i < 2; ++i)
9866 	      {
9867 	         var = (*consvars)[i];
9868 	         weight = ABS((*consvals)[i]);
9869 	
9870 	         SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, SCIPgetSymgraphVarnodeidx(scip, graph, var),
9871 	               TRUE, weight) );
9872 	         SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var),
9873 	               TRUE, weight) );
9874 	      }
9875 	   }
9876 	
9877 	   return SCIP_OKAY;
9878 	}
9879 	
9880 	/** tries to add gadget for finding signed permutations of even univariate operators
9881 	 *
9882 	 *  We handle two cases. First, if a univariate operator is even and has a variable
9883 	 *  as child, negating the child is signed permutation. Second, the univariate operator
9884 	 *  is even and has a weighted sum of two variables as child.
9885 	 */
9886 	static
9887 	SCIP_RETCODE tryAddGadgetEvenOperator(
9888 	   SCIP*                 scip,               /**< SCIP pointer */
9889 	   SCIP_EXPR*            expr,               /**< expression for which gadget is tried to be added */
9890 	   SCIP_CONS*            cons,               /**< constraint containing expression */
9891 	   SYM_GRAPH*            graph,              /**< symmetry detection graph to be extended by gadget */
9892 	   int                   parentidx,          /**< index of parent node in symmetry detection graph for gadget */
9893 	   SCIP_Bool             hasparentcoef,      /**< whether the parent gives a coefficient to the expression */
9894 	   SCIP_Real             parentcoef,         /**< the parent coefficient (if it exists) */
9895 	   SCIP_VAR***           consvars,           /**< pointer to allocated array to store temporary variables */
9896 	   SCIP_Real**           consvals,           /**< pointer to allocated arrat to store temporary values */
9897 	   int*                  maxnconsvars,       /**< pointer to maximum number consvars/consvals can hold */
9898 	   SCIP_HASHSET*         handledexprs,       /**< hashset to store handled expressions */
9899 	   SCIP_Bool*            success             /**< pointer to store whether gadget could be added successfully */
9900 	   )
9901 	{
9902 	   SCIP_EXPR* child;
9903 	   SCIP_Real val = 0.0;
9904 	   SCIP_Bool hasval = FALSE;
9905 	
9906 	   assert(scip != NULL);
9907 	   assert(expr != NULL);
9908 	   assert(graph != NULL);
9909 	   assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
9910 	   assert(consvars != NULL);
9911 	   assert(consvals != NULL);
9912 	   assert(maxnconsvars != NULL);
9913 	   assert(*maxnconsvars > 0);
9914 	   assert(handledexprs != NULL);
9915 	   assert(success != NULL);
9916 	
9917 	   *success = FALSE;
9918 	
9919 	   /* ignore variable or value expressions */
9920 	   if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
9921 	      return SCIP_OKAY;
9922 	   assert(SCIPexprGetNChildren(expr) > 0);
9923 	
9924 	   /* ignore operators with too many children */
9925 	   if( SCIPexprGetNChildren(expr) > 1 )
9926 	      return SCIP_OKAY;
9927 	
9928 	   /* check whether operator is even */
9929 	   if( !isEvenOperator(scip, expr, &hasval, &val) )
9930 	      return SCIP_OKAY;
9931 	
9932 	   /* we can only treat the operator if its child is a variable or a sum */
9933 	   child = SCIPexprGetChildren(expr)[0];
9934 	   if( SCIPisExprVar(scip, child) )
9935 	   {
9936 	      SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
9937 	            hasval, val, consvars, consvals, maxnconsvars, success) );
9938 	   }
9939 	   else if( SCIPisExprSum(scip, child) )
9940 	   {
9941 	      SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
9942 	            hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
9943 	   }
9944 	
9945 	   if( *success )
9946 	   {
9947 	      SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
9948 	   }
9949 	
9950 	   return SCIP_OKAY;
9951 	}
9952 	
9953 	/** compares two variable pointers */
9954 	static
9955 	SCIP_DECL_SORTINDCOMP(SCIPsortVarPtr)
9956 	{  /*lint --e{715}*/
9957 	   SCIP_VAR** vars;
9958 	   SCIP_VAR* var1;
9959 	   SCIP_VAR* var2;
9960 	
9961 	   vars = (SCIP_VAR**) dataptr;
9962 	
9963 	   var1 = vars[ind1];
9964 	   var2 = vars[ind2];
9965 	   assert(var1 != NULL);
9966 	   assert(var2 != NULL);
9967 	
9968 	   /* sort variables by their unique index */
9969 	   if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
9970 	      return -1;
9971 	   if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
9972 	      return 1;
9973 	
9974 	   return 0;
9975 	}
9976 	
9977 	/** gets domain center of a variable which has not semi-infinite domain */
9978 	static
9979 	SCIP_Real getDomainCenter(
9980 	   SCIP*                 scip,               /**< SCIP pointer */
9981 	   SCIP_VAR*             var                 /**< variable */
9982 	   )
9983 	{
9984 	   SCIP_Real ub;
9985 	   SCIP_Real lb;
9986 	
9987 	   ub = SCIPvarGetUbGlobal(var);
9988 	   lb = SCIPvarGetLbGlobal(var);
9989 	
9990 	   assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
9991 	
9992 	   if ( SCIPisInfinity(scip, ub) )
9993 	      return 0.0;
9994 	
9995 	   return (ub + lb) / 2;
9996 	}
9997 	
9998 	/** tries to add gadget for finding signed permutations for squared differences in a sum expression */
9999 	static
10000	SCIP_RETCODE tryAddGadgetSquaredDifference(
10001	   SCIP*                 scip,               /**< SCIP pointer */
10002	   SCIP_EXPR*            sumexpr,            /**< sum expression */
10003	   SCIP_CONS*            cons,               /**< constraint containing the sum expression */
10004	   SYM_GRAPH*            graph,              /**< symmetry detection graph to be extended by gadget */
10005	   int                   sumnodeidx,         /**< index of sum node in symmetry detection graph for gadget */
10006	   SCIP_VAR***           consvars,           /**< pointer to allocated array to store temporary variables */
10007	   SCIP_Real**           consvals,           /**< pointer to allocated arrat to store temporary values */
10008	   int*                  maxnconsvars,       /**< pointer to maximum number consvars/consvals can hold */
10009	   SCIP_HASHSET*         handledexprs        /**< hashset to store handled expressions */
10010	   )
10011	{
10012	   SYM_EXPRDATA* symdata;
10013	   SCIP_EXPR** children;
10014	   SCIP_EXPR** powexprs;
10015	   SCIP_EXPR** prodexprs;
10016	   SCIP_EXPR* child;
10017	   SCIP_VAR**  powvars;
10018	   SCIP_VAR** prodvars;
10019	   SCIP_VAR* actvar;
10020	   SCIP_VAR* actvar2;
10021	   SCIP_VAR* var;
10022	   SCIP_VAR* var2;
10023	   SCIP_Real* sumcoefs;
10024	   SCIP_Real constant;
10025	   SCIP_Real constant2;
10026	   SCIP_Real val;
10027	   SCIP_Real val2;
10028	   SCIP_Bool* powexprused = NULL;
10029	   int* powperm = NULL;
10030	   int* prodperm = NULL;
10031	   int nchildren;
10032	   int nlocvars;
10033	   int nodeidx;
10034	   int coefnodeidx1;
10035	   int coefnodeidx2;
10036	   int cnt;
10037	   int i;
10038	   int j;
10039	   int nterms;
10040	   int npowexprs = 0;
10041	   int nprodexprs = 0;
10042	   int powcoef = 0;
10043	
10044	   assert(scip != NULL);
10045	   assert(sumexpr != NULL);
10046	   assert(cons != NULL);
10047	   assert(SCIPisExprSum(scip, sumexpr));
10048	   assert(consvars != NULL);
10049	   assert(consvals != NULL);
10050	   assert(maxnconsvars != NULL);
10051	   assert(*maxnconsvars > 0);
10052	   assert(handledexprs != NULL);
10053	
10054	   /* iterate over sum expression and extract all power and product expressions */
10055	   sumcoefs = SCIPgetCoefsExprSum(sumexpr);
10056	   children = SCIPexprGetChildren(sumexpr);
10057	   nchildren = SCIPexprGetNChildren(sumexpr);
10058	   SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
10059	   SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
10060	   SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
10061	   SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
10062	
10063	   /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
10064	   /** @todo make this work in a more general case */
10065	   for( i = 0; i < nchildren; ++i )
10066	   {
10067	      if( SCIPisExprPower(scip, children[i]) )
10068	      {
10069	         SCIP_Real exponent;
10070	
10071	         /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
10072	         if( powcoef == 0 )
10073	         {
10074	            if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
10075	               powcoef = (int) SCIPround(scip, sumcoefs[i]);
10076	         }
10077	         else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
10078	            continue;
10079	
10080	         /* we only store power expressions if their child is a variable */
10081	         assert(SCIPexprGetNChildren(children[i]) == 1);
10082	         child = SCIPexprGetChildren(children[i])[0];
10083	         if( !SCIPisExprVar(scip, child) )
10084	            continue;
10085	
10086	         /* the power is required to be a 2 */
10087	         SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
10088	         assert(symdata != NULL);
10089	         assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10090	
10091	         exponent = SCIPgetSymExprdataConstants(symdata)[0];
10092	         SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10093	
10094	         if( !SCIPisEQ(scip, exponent, 2.0) )
10095	            continue;
10096	
10097	         /* we only store power expressions if the child is not multi-aggregated */
10098	         var = SCIPgetVarExprVar(child);
10099	         if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR )
10100	         {
10101	            powexprs[npowexprs] = children[i];
10102	            powvars[npowexprs++] = var;
10103	         }
10104	      }
10105	      else if( SCIPisExprProduct(scip, children[i]) )
10106	      {
10107	         /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
10108	         if( powcoef == 0 )
10109	         {
10110	            if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
10111	               powcoef = (int) -SCIPround(scip, sumcoefs[i]);
10112	         }
10113	         else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
10114	            continue;
10115	
10116	         /* we only store power expressions if they have exactly two children being variables */
10117	         if( SCIPexprGetNChildren(children[i]) != 2 )
10118	            continue;
10119	         if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
10120	            || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
10121	            continue;
10122	
10123	         var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
10124	         var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
10125	
10126	         /* we only store product expressions if the children are not multi-aggregated */
10127	         if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR
10128	            && SCIPvarGetStatus(var2) != SCIP_VARSTATUS_MULTAGGR )
10129	         {
10130	            prodexprs[nprodexprs] = children[i];
10131	            prodvars[nprodexprs++] = var;
10132	            prodexprs[nprodexprs] = children[i];
10133	            prodvars[nprodexprs++] = var2;
10134	         }
10135	      }
10136	   }
10137	
10138	   if( npowexprs == 0 || nprodexprs != npowexprs )
10139	      goto FREEMEMORY;
10140	
10141	   /* check whether the power variables and product variables match */
10142	   SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
10143	   SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
10144	
10145	   SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
10146	   SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
10147	
10148	   for( i = 0; i < npowexprs; ++i )
10149	   {
10150	      if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
10151	         goto FREEMEMORY;
10152	   }
10153	
10154	   /* if we reach this line, the variables match: we have found a potential norm constraint */
10155	   assert(npowexprs % 2 == 0);
10156	   nterms = npowexprs / 2;
10157	   SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
10158	
10159	   /* add gadget of each squared difference term */
10160	   cnt = 0;
10161	   for( i = 0; i < nterms; ++i )
10162	   {
10163	      SCIP_Bool var1found = FALSE;
10164	      SCIP_Bool var2found = FALSE;
10165	
10166	      (*consvals)[0] = 1.0;
10167	      (*consvars)[0] = prodvars[cnt++];
10168	      constant = 0.0;
10169	      nlocvars = 1;
10170	
10171	      SCIP_CALL( SCIPgetActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals,
10172	            &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10173	
10174	      if( nlocvars != 1 )
10175	      {
10176	         ++cnt;
10177	         continue;
10178	      }
10179	      actvar = (*consvars)[0];
10180	      val = (*consvals)[0];
10181	
10182	      (*consvals)[0] = 1.0;
10183	      (*consvars)[0] = prodvars[cnt++];
10184	      constant2 = 0.0;
10185	      nlocvars = 1;
10186	
10187	      SCIP_CALL( SCIPgetActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals,
10188	            &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
10189	
10190	      if( nlocvars != 1 )
10191	         continue;
10192	      actvar2 = (*consvars)[0];
10193	      val2 = (*consvals)[0];
10194	
10195	      /* we cannot handle the pair of variables if their constant/scalar differs or one variable
10196	       * cannot be centered at the origin or they are not centered around the same point
10197	       */
10198	      if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
10199	         || (SCIPisInfinity(scip, SCIPvarGetUbGlobal(actvar)) != SCIPisInfinity(scip, -SCIPvarGetLbGlobal(actvar)))
10200	         || (SCIPisInfinity(scip, SCIPvarGetUbGlobal(actvar2)) != SCIPisInfinity(scip, -SCIPvarGetLbGlobal(actvar2)))
10201	         || (SCIPisInfinity(scip, SCIPvarGetUbGlobal(actvar)) != SCIPisInfinity(scip, SCIPvarGetLbGlobal(actvar2)))
10202	         || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
10203	         continue;
10204	
10205	      /* add gadget */
10206	      SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
10207	      SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
10208	      SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
10209	
10210	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
10211	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
10212	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
10213	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10214	            SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10215	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10216	            SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10217	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10218	            SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10219	      SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10220	            SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10221	
10222	      /* mark product expression as handled */
10223	      SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
10224	
10225	      /* find corresponding unused power expressions and mark them as handled */
10226	      for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
10227	      {
10228	         if( powexprused[j] )
10229	            continue;
10230	         assert(cnt >= 2);
10231	
10232	         if( !var1found && powvars[j] == prodvars[cnt - 2] )
10233	         {
10234	            SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10235	            powexprused[j] = TRUE;
10236	         }
10237	         else if( !var2found && powvars[j] == prodvars[cnt - 1] )
10238	         {
10239	            SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10240	            powexprused[j] = TRUE;
10241	         }
10242	      }
10243	   }
10244	
10245	 FREEMEMORY:
10246	   SCIPfreeBufferArrayNull(scip, &powexprused);
10247	   SCIPfreeBufferArrayNull(scip, &prodperm);
10248	   SCIPfreeBufferArrayNull(scip, &powperm);
10249	   SCIPfreeBufferArray(scip, &prodvars);
10250	   SCIPfreeBufferArray(scip, &powvars);
10251	   SCIPfreeBufferArray(scip, &prodexprs);
10252	   SCIPfreeBufferArray(scip, &powexprs);
10253	
10254	   return SCIP_OKAY;
10255	}
10256	
10257	/** adds symmetry information of constraint to a symmetry detection graph */
10258	static
10259	SCIP_RETCODE addSymmetryInformation(
10260	   SCIP*                 scip,               /**< SCIP pointer */
10261	   SYM_SYMTYPE           symtype,            /**< type of symmetries that need to be added */
10262	   SCIP_CONS*            cons,               /**< constraint */
10263	   SYM_GRAPH*            graph,              /**< symmetry detection graph */
10264	   SCIP_Bool*            success             /**< pointer to store whether symmetry information could be added */
10265	   )
10266	{ /*lint --e{850}*/
10267	   SCIP_EXPRITER* it;
10268	   SCIP_HASHSET* handledexprs;
10269	   SCIP_EXPR* rootexpr;
10270	   SCIP_EXPR* expr;
10271	   SCIP_VAR** consvars;
10272	   SCIP_Real* consvals;
10273	   SCIP_Real constant;
10274	   SCIP_Real parentcoef = 0.0;
10275	   int* openidx;
10276	   int maxnopenidx;
10277	   int parentidx;
10278	   int nconsvars;
10279	   int maxnconsvars;
10280	   int nlocvars;
10281	   int nopenidx = 0;
10282	   int consnodeidx;
10283	   int nodeidx;
10284	   int i;
10285	   SCIP_Bool iscolored;
10286	   SCIP_Bool hasparentcoef;
10287	
10288	   assert(scip != NULL);
10289	   assert(cons != NULL);
10290	   assert(graph != NULL);
10291	   assert(success != NULL);
10292	
10293	   /* store lhs/rhs */
10294	   SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons,
10295	         SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
10296	
10297	   rootexpr = SCIPgetExprNonlinear(cons);
10298	   assert(rootexpr != NULL);
10299	
10300	   /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
10301	   expr = SCIPgetExprNonlinear(cons);
10302	   assert(expr != NULL);
10303	
10304	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
10305	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
10306	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_LEAVEEXPR);
10307	
10308	   /* find potential number of nodes in graph */
10309	   maxnopenidx = 0;
10310	   for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
10311	   {
10312	      if( SCIPexpriterGetStageDFS(it) == SCIP_EXPRITER_LEAVEEXPR )
10313	         continue;
10314	
10315	      ++maxnopenidx;
10316	   }
10317	
10318	   SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
10319	
10320	   maxnconsvars = SCIPgetNVars(scip);
10321	   SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
10322	   SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
10323	
10324	   /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
10325	   SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
10326	
10327	   /* iterate over expression tree and store nodes/edges */
10328	   expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
10329	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
10330	   SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_LEAVEEXPR);
10331	
10332	   for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10333	   {
10334	      /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
10335	      if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
10336	      {
10337	         SCIP_EXPR* baseexpr;
10338	
10339	         baseexpr = expr;
10340	         while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
10341	            expr = SCIPexpriterGetNext(it);
10342	
10343	         SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
10344	
10345	         /* leave the expression */
10346	         continue;
10347	      }
10348	
10349	      /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
10350	      if( SCIPexpriterGetStageDFS(it) == SCIP_EXPRITER_LEAVEEXPR )
10351	      {
10352	         --nopenidx;
10353	         continue;
10354	      }
10355	      assert(SCIPexpriterGetStageDFS(it) == SCIP_EXPRITER_ENTEREXPR);
10356	
10357	      /* find parentidx */
10358	      if( expr == rootexpr )
10359	         parentidx = consnodeidx;
10360	      else
10361	      {
10362	         assert(nopenidx >= 1);
10363	         parentidx = openidx[nopenidx - 1];
10364	      }
10365	
10366	      /* possibly find a coefficient assigned to the expression by the parent */
10367	      hasparentcoef = FALSE;
10368	      if ( expr != rootexpr )
10369	      {
10370	         SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
10371	      }
10372	
10373	      /* deal with different kinds of expressions and store them in the symmetry data structure */
10374	      if( SCIPisExprVar(scip, expr) )
10375	      {
10376	         /* needed to correctly reset value when leaving expression */
10377	         SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10378	
10379	         openidx[nopenidx++] = -1;
10380	
10381	         assert(maxnconsvars > 0);
10382	         assert(parentidx > 0);
10383	
10384	         /* if the parent assigns the variable a coefficient, introduce an intermediate node */
10385	         if( hasparentcoef )
10386	         {
10387	            SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
10388	
10389	            SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
10390	            parentidx = nodeidx;
10391	         }
10392	
10393	         /* connect (aggregation of) variable expression with its parent */
10394	         nconsvars = 1;
10395	         consvars[0] = SCIPgetVarExprVar(expr);
10396	         consvals[0] = 1.0;
10397	         constant = 0.0;
10398	
10399	         SCIP_CALL( SCIPgetActiveVariables(scip, symtype, &consvars, &consvals,
10400	               &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
10401	
10402	         /* check whether variable is aggregated */
10403	         if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
10404	         {
10405	            int thisidx;
10406	
10407	            SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
10408	            SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
10409	
10410	            parentidx = thisidx;
10411	         }
10412	         SCIP_CALL( SCIPaddSymgraphVarAggegration(scip, graph, parentidx, consvars, consvals,
10413	               nconsvars, constant) );
10414	      }
10415	      else if( SCIPisExprValue(scip, expr) )
10416	      {
10417	         assert(parentidx > 0);
10418	
10419	         SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
10420	
10421	         SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
10422	
10423	         /* needed to correctly reset value when leaving expression */
10424	         SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10425	
10426	         openidx[nopenidx++] = -1;
10427	      }
10428	      else
10429	      {
10430	         SCIP_Bool usedefaultgadget = TRUE;
10431	
10432	         assert(expr == rootexpr || parentidx > 0);
10433	         assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
10434	
10435	         if( SCIPisExprSum(scip, expr) )
10436	         {
10437	            /* deal with sum expressions differently, because we can possibly aggregate linear sums */
10438	            SCIP_EXPR** children;
10439	            int sumidx;
10440	            int optype;
10441	            int childidx = 0;
10442	
10443	            /* sums are handled by a special gadget */
10444	            usedefaultgadget = FALSE;
10445	
10446	            /* extract all children being variables and compute the sum of active variables expression */
10447	            nlocvars = 0;
10448	            children = SCIPexprGetChildren(expr);
10449	
10450	            SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
10451	
10452	            for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
10453	            {
10454	               if( !SCIPisExprVar(scip, children[childidx]) )
10455	                  continue;
10456	
10457	               consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
10458	               consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
10459	
10460	               /* store that we have already handled this expression */
10461	               SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
10462	            }
10463	
10464	            constant = SCIPgetConstantExprSum(expr);
10465	
10466	            SCIP_CALL( SCIPgetActiveVariables(scip, symtype, &consvars, &consvals,
10467	                  &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10468	
10469	            SCIP_CALL( SCIPgetSymOpNodeType(scip, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), &optype) );
10470	
10471	            SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
10472	            SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
10473	
10474	            /* add the linear part of the sum */
10475	            SCIP_CALL( SCIPaddSymgraphVarAggegration(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
10476	
10477	            SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10478	
10479	            /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
10480	            if( symtype == SYM_SYMTYPE_SIGNPERM )
10481	            {
10482	               SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
10483	                     &consvars, &consvals, &maxnconsvars, handledexprs) );
10484	            }
10485	
10486	            /* store sumidx for children that have not been treated */
10487	            openidx[nopenidx++] = sumidx;
10488	         }
10489	         else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
10490	         {
10491	            SCIP_Bool succ;
10492	
10493	            SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
10494	                  parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10495	
10496	            if( succ )
10497	            {
10498	               usedefaultgadget = FALSE;
10499	               SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10500	            }
10501	         }
10502	         else if( symtype == SYM_SYMTYPE_SIGNPERM )
10503	         {
10504	            SCIP_Bool succ;
10505	
10506	            /* we can find more signed permutations for even univariate operators */
10507	            SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
10508	                  &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10509	
10510	            if( succ )
10511	            {
10512	               usedefaultgadget = FALSE;
10513	               SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10514	            }
10515	         }
10516	
10517	         if( usedefaultgadget )
10518	         {
10519	            int opidx;
10520	            int optype;
10521	
10522	            SCIP_CALL( SCIPgetSymOpNodeType(scip, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), &optype) );
10523	            SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
10524	            SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
10525	
10526	            /* possibly add constants of expression */
10527	            if( SCIPexprhdlrHasGetSymData(SCIPexprGetHdlr(expr)) )
10528	            {
10529	               SYM_EXPRDATA* symdata;
10530	
10531	               SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
10532	               assert(symdata != NULL);
10533	
10534	               /* if expression has multiple constants, assign colors to edges to distinguish them */
10535	               iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
10536	               for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
10537	               {
10538	                  SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
10539	                  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
10540	               }
10541	
10542	               SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10543	            }
10544	
10545	            SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10546	
10547	            openidx[nopenidx++] = opidx;
10548	         }
10549	      }
10550	   }
10551	
10552	   SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
10553	   SCIPfreeBufferArray(scip, &consvals);
10554	   SCIPfreeBufferArray(scip, &consvars);
10555	   SCIPfreeBufferArray(scip, &openidx);
10556	   SCIPfreeExpriter(&it);
10557	
10558	   return SCIP_OKAY;
10559	}
10560	
10561	/*
10562	 * Callback methods of constraint handler
10563	 */
10564	
10565	/** copy method for constraint handler plugins (called when SCIP copies plugins) */
10566	static
10567	SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
10568	{  /*lint --e{715}*/
10569	   SCIP_CONSHDLR*     targetconshdlr;
10570	   SCIP_CONSHDLRDATA* sourceconshdlrdata;
10571	   int                i;
10572	
10573	   assert(scip != NULL);
10574	   assert(conshdlr != NULL);
10575	   assert(valid != NULL);
10576	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
10577	
10578	   /* create basic data of constraint handler and include it to scip */
10579	   SCIP_CALL( SCIPincludeConshdlrNonlinear(scip) );
10580	
10581	   targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10582	   assert(targetconshdlr != NULL);
10583	   assert(targetconshdlr != conshdlr);
10584	
10585	   sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
10586	   assert(sourceconshdlrdata != NULL);
10587	
10588	   /* copy nonlinear handlers */
10589	   for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
10590	   {
10591	      SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
10592	   }
10593	
10594	   *valid = TRUE;
10595	
10596	   return SCIP_OKAY;
10597	}
10598	
10599	/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
10600	static
10601	SCIP_DECL_CONSFREE(consFreeNonlinear)
10602	{  /*lint --e{715}*/
10603	   SCIP_CONSHDLRDATA* conshdlrdata;
10604	   int i;
10605	
10606	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10607	   assert(conshdlrdata != NULL);
10608	
10609	   /* free nonlinear handlers */
10610	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10611	   {
10612	      SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
10613	      assert(conshdlrdata->nlhdlrs[i] == NULL);
10614	   }
10615	   SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
10616	   conshdlrdata->nlhdlrssize = 0;
10617	
10618	   /* free upgrade functions */
10619	   for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
10620	   {
10621	      assert(conshdlrdata->consupgrades[i] != NULL);
10622	      SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
10623	   }
10624	   SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
10625	
10626	   SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
10627	
10628	   SCIPqueueFree(&conshdlrdata->reversepropqueue);
10629	
10630	   if( conshdlrdata->vp_randnumgen != NULL )
10631	      SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
10632	
10633	   /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
10634	   for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
10635	   {
10636	      if( conshdlrdata->vp_lp[i] != NULL )
10637	      {
10638	         SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
10639	      }
10640	   }
10641	
10642	   assert(conshdlrdata->branchrandnumgen == NULL);
10643	
10644	   assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
10645	   SCIPhashmapFree(&conshdlrdata->var2expr);
10646	
10647	   SCIPfreeBlockMemory(scip, &conshdlrdata);
10648	   SCIPconshdlrSetData(conshdlr, NULL);
10649	
10650	   return SCIP_OKAY;
10651	}
10652	
10653	
10654	/** initialization method of constraint handler (called after problem was transformed) */
10655	static
10656	SCIP_DECL_CONSINIT(consInitNonlinear)
10657	{  /*lint --e{715}*/
10658	   SCIP_CONSHDLRDATA* conshdlrdata;
10659	   int i;
10660	
10661	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10662	   assert(conshdlrdata != NULL);
10663	
10664	   /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
10665	   conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
10666	   /* set to 1 so it is larger than initial value of lastenforound in exprs */
10667	   conshdlrdata->enforound = 1;
10668	   /* reset numbering for auxiliary variables */
10669	   conshdlrdata->auxvarid = 0;
10670	
10671	   for( i = 0; i < nconss; ++i )
10672	   {
10673	      SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
10674	      SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
10675	   }
10676	
10677	   /* sort nonlinear handlers by detection priority, in decreasing order */
10678	   if( conshdlrdata->nnlhdlrs > 1 )
10679	      SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
10680	
10681	   /* get heuristics for later use */
10682	   conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
10683	   conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
10684	
10685	   /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
10686	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10687	   {
10688	      SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
10689	   }
10690	
10691	   /* reset statistics in constraint handler */
10692	   conshdlrdata->nweaksepa = 0;
10693	   conshdlrdata->ntightenlp = 0;
10694	   conshdlrdata->ndesperatebranch = 0;
10695	   conshdlrdata->ndesperatecutoff = 0;
10696	   conshdlrdata->ndesperatetightenlp = 0;
10697	   conshdlrdata->nforcelp = 0;
10698	   SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
10699	   conshdlrdata->ncanonicalizecalls = 0;
10700	
10701	#ifdef ENFOLOGFILE
10702	   ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
10703	#endif
10704	
10705	   return SCIP_OKAY;
10706	}
10707	
10708	
10709	/** deinitialization method of constraint handler (called before transformed problem is freed) */
10710	static
10711	SCIP_DECL_CONSEXIT(consExitNonlinear)
10712	{  /*lint --e{715}*/
10713	   SCIP_CONSHDLRDATA* conshdlrdata;
10714	   SCIP_CONS** consssorted;
10715	   int i;
10716	
10717	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10718	   assert(conshdlrdata != NULL);
10719	
10720	   if( nconss > 0 )
10721	   {
10722	      /* for better performance of dropVarEvents, we sort by index, descending */
10723	      SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
10724	      SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
10725	
10726	      for( i = 0; i < nconss; ++i )
10727	      {
10728	         SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
10729	         SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
10730	      }
10731	
10732	      SCIPfreeBufferArray(scip, &consssorted);
10733	   }
10734	
10735	   conshdlrdata->subnlpheur = NULL;
10736	   conshdlrdata->trysolheur = NULL;
10737	
10738	   if( conshdlrdata->vp_randnumgen != NULL )
10739	      SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
10740	
10741	   /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
10742	   for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
10743	   {
10744	      if( conshdlrdata->vp_lp[i] != NULL )
10745	      {
10746	         SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
10747	      }
10748	   }
10749	
10750	   if( conshdlrdata->branchrandnumgen != NULL )
10751	      SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
10752	
10753	   /* deinitialize nonlinear handlers */
10754	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10755	   {
10756	      SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
10757	   }
10758	
10759	   ENFOLOG(
10760	   if( enfologfile != NULL )
10761	   {
10762	      fclose(enfologfile);
10763	      enfologfile = NULL;
10764	   })
10765	
10766	   return SCIP_OKAY;
10767	}
10768	
10769	
10770	/** presolving initialization method of constraint handler (called when presolving is about to begin) */
10771	#ifdef SCIP_DISABLED_CODE
10772	static
10773	SCIP_DECL_CONSINITPRE(consInitpreNonlinear)
10774	{  /*lint --e{715}*/
10775	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10776	   SCIPABORT(); /*lint --e{527}*/
10777	
10778	   return SCIP_OKAY;
10779	}
10780	#else
10781	#define consInitpreNonlinear NULL
10782	#endif
10783	
10784	
10785	/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
10786	static
10787	SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
10788	{  /*lint --e{715}*/
10789	   SCIP_Bool infeasible;
10790	
10791	   if( nconss == 0 )
10792	      return SCIP_OKAY;
10793	
10794	   /* skip some extra work if already known to be infeasible */
10795	   if( SCIPgetStatus(scip) == SCIP_STATUS_INFEASIBLE )
10796	      return SCIP_OKAY;
10797	
10798	   /* simplify constraints and replace common subexpressions */
10799	   SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
10800	
10801	   /* currently SCIP does not offer to communicate this,
10802	    * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
10803	    * or if a constraint expression became constant
10804	    * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
10805	    */
10806	   /* assert(!infeasible); */
10807	
10808	   /* tell SCIP that we have something nonlinear */
10809	   SCIPenableNLP(scip);
10810	
10811	   return SCIP_OKAY;
10812	}
10813	
10814	
10815	/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
10816	static
10817	SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
10818	{  /*lint --e{715}*/
10819	   SCIP_CONSHDLRDATA* conshdlrdata;
10820	   int i;
10821	
10822	   /* skip remaining initializations if we have solved already
10823	    * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
10824	    * assumes nonempty activities in expressions
10825	    */
10826	   switch( SCIPgetStatus(scip) )
10827	   {
10828	      case SCIP_STATUS_OPTIMAL:
10829	      case SCIP_STATUS_INFEASIBLE:
10830	      case SCIP_STATUS_UNBOUNDED:
10831	      case SCIP_STATUS_INFORUNBD:
10832	         return SCIP_OKAY;
10833	      default: ;
10834	   } /*lint !e788 */
10835	
10836	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10837	   assert(conshdlrdata != NULL);
10838	
10839	   /* reset one of the number of detections counter to count only current round */
10840	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10841	      SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
10842	
10843	   SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
10844	
10845	   /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
10846	   if( conshdlrdata->branchpscostweight > 0.0 )
10847	   {
10848	      SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
10849	      if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
10850	      {
10851	         SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
10852	         SCIPABORT();
10853	         return SCIP_INVALIDDATA;
10854	      }
10855	   }
10856	
10857	   return SCIP_OKAY;
10858	}
10859	
10860	
10861	/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
10862	static
10863	SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
10864	{  /*lint --e{715}*/
10865	   SCIP_CONSHDLRDATA* conshdlrdata;
10866	
10867	   SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
10868	
10869	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10870	   assert(conshdlrdata != NULL);
10871	
10872	   /* free hash table for bilinear terms */
10873	   SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
10874	
10875	   /* reset flag to allow another call of presolSingleLockedVars() after a restart */
10876	   conshdlrdata->checkedvarlocks = FALSE;
10877	
10878	   /* drop catching new solution event, if catched before */
10879	   if( conshdlrdata->newsoleventfilterpos >= 0 )
10880	   {
10881	      SCIP_EVENTHDLR* eventhdlr;
10882	
10883	      eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
10884	      assert(eventhdlr != NULL);
10885	
10886	      SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
10887	      conshdlrdata->newsoleventfilterpos = -1;
10888	   }
10889	
10890	   return SCIP_OKAY;
10891	}
10892	
10893	
10894	/** frees specific constraint data */
10895	static
10896	SCIP_DECL_CONSDELETE(consDeleteNonlinear)
10897	{  /*lint --e{715}*/
10898	   assert(consdata != NULL);
10899	   assert(*consdata != NULL);
10900	   assert((*consdata)->expr != NULL);
10901	
10902	   /* constraint locks should have been removed */
10903	   assert((*consdata)->nlockspos == 0);
10904	   assert((*consdata)->nlocksneg == 0);
10905	
10906	   /* free variable expressions */
10907	   SCIP_CALL( freeVarExprs(scip, *consdata) );
10908	
10909	   SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
10910	
10911	   /* free nonlinear row representation */
10912	   if( (*consdata)->nlrow != NULL )
10913	   {
10914	      SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
10915	   }
10916	
10917	   SCIPfreeBlockMemory(scip, consdata);
10918	
10919	   return SCIP_OKAY;
10920	}
10921	
10922	
10923	/** transforms constraint data into data belonging to the transformed problem */
10924	static
10925	SCIP_DECL_CONSTRANS(consTransNonlinear)
10926	{  /*lint --e{715}*/
10927	   SCIP_EXPR* targetexpr;
10928	   SCIP_CONSDATA* sourcedata;
10929	
10930	   sourcedata = SCIPconsGetData(sourcecons);
10931	   assert(sourcedata != NULL);
10932	
10933	   /* get a copy of sourceexpr with transformed vars */
10934	   SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
10935	   assert(targetexpr != NULL);  /* SCIPduplicateExpr cannot fail */
10936	
10937	   /* create transformed cons (only captures targetexpr, no need to copy again) */
10938	   SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
10939	      targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
10940	      SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
10941	      SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
10942	      SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
10943	      SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
10944	
10945	   /* release target expr */
10946	   SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
10947	
10948	   return SCIP_OKAY;
10949	}
10950	
10951	
10952	/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
10953	static
10954	SCIP_DECL_CONSINITLP(consInitlpNonlinear)
10955	{  /*lint --e{715}*/
10956	   SCIP_CONSHDLRDATA* conshdlrdata;
10957	
10958	   /* create auxiliary variables and call separation initialization callbacks of the expression handlers
10959	    * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
10960	    *   during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
10961	    *   for now, there is an assert in detectNlhdlrs to require initial if separated
10962	    */
10963	   SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
10964	
10965	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
10966	   assert(conshdlrdata != NULL);
10967	
10968	   /* catch new solution event */
10969	   if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
10970	   {
10971	      SCIP_EVENTHDLR* eventhdlr;
10972	
10973	      eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
10974	      assert(eventhdlr != NULL);
10975	
10976	      SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
10977	         eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
10978	   }
10979	
10980	   /* collect all bilinear terms for which an auxvar is present
10981	    * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
10982	    * addition (and removal?) of constraints during solve
10983	    * this is typically the majority of constraints, but the method should be made more flexible
10984	    */
10985	   SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
10986	
10987	   return SCIP_OKAY;
10988	}
10989	
10990	
10991	/** separation method of constraint handler for LP solutions */
10992	static
10993	SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
10994	{  /*lint --e{715}*/
10995	   SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
10996	
10997	   return SCIP_OKAY;
10998	}
10999	
11000	
11001	/** separation method of constraint handler for arbitrary primal solutions */
11002	static
11003	SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
11004	{  /*lint --e{715}*/
11005	   SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11006	
11007	   return SCIP_OKAY;
11008	}
11009	
11010	
11011	/** constraint enforcing method of constraint handler for LP solutions */
11012	static
11013	SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
11014	{  /*lint --e{715}*/
11015	   SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11016	
11017	   return SCIP_OKAY;
11018	}
11019	
11020	
11021	/** constraint enforcing method of constraint handler for relaxation solutions */
11022	static
11023	SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
11024	{  /*lint --e{715}*/
11025	   SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11026	
11027	   return SCIP_OKAY;
11028	}
11029	
11030	
11031	/** constraint enforcing method of constraint handler for pseudo solutions */
11032	static
11033	SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
11034	{  /*lint --e{715}*/
11035	   SCIP_RESULT propresult;
11036	   SCIP_Longint soltag;
11037	   int nchgbds;
11038	   int nnotify;
11039	   int c;
11040	
11041	   soltag = SCIPgetExprNewSoltag(scip);
11042	
11043	   *result = SCIP_FEASIBLE;
11044	   for( c = 0; c < nconss; ++c )
11045	   {
11046	      SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
11047	
11048	      if( isConsViolated(scip, conss[c]) )
11049	         *result = SCIP_INFEASIBLE;
11050	   }
11051	
11052	   if( *result == SCIP_FEASIBLE )
11053	      return SCIP_OKAY;
11054	
11055	   /* try to propagate
11056	    * TODO obey propinenfo parameter, but we need something to recognize cutoff
11057	    */
11058	   nchgbds = 0;
11059	   SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11060	
11061	   if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
11062	   {
11063	      *result = propresult;
11064	      return SCIP_OKAY;
11065	   }
11066	
11067	   /* register all unfixed variables in all violated constraints as branching candidates */
11068	   SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11069	   if( nnotify > 0 )
11070	   {
11071	      SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11072	
11073	      return SCIP_OKAY;
11074	   }
11075	
11076	   SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11077	   *result = SCIP_SOLVELP;
11078	   ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11079	
11080	   return SCIP_OKAY;
11081	}
11082	
11083	
11084	/** feasibility check method of constraint handler for integral solutions */
11085	static
11086	SCIP_DECL_CONSCHECK(consCheckNonlinear)
11087	{  /*lint --e{715}*/
11088	   SCIP_CONSHDLRDATA* conshdlrdata;
11089	   SCIP_CONSDATA*     consdata;
11090	   SCIP_Real          maxviol;
11091	   SCIP_Bool          maypropfeasible;
11092	   SCIP_Longint       soltag;
11093	   int c;
11094	
11095	   assert(scip != NULL);
11096	   assert(conshdlr != NULL);
11097	   assert(conss != NULL || nconss == 0);
11098	   assert(result != NULL);
11099	
11100	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11101	   assert(conshdlrdata != NULL);
11102	
11103	   *result = SCIP_FEASIBLE;
11104	   soltag = SCIPgetExprNewSoltag(scip);
11105	   maxviol = 0.0;
11106	   maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11107	      && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING;
11108	
11109	   if( maypropfeasible && (sol == NULL || SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_LPSOL) && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
11110	      maypropfeasible = FALSE;
11111	
11112	   /* check nonlinear constraints for feasibility */
11113	   for( c = 0; c < nconss; ++c )
11114	   {
11115	      assert(conss != NULL && conss[c] != NULL);
11116	      SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11117	
11118	      if( isConsViolated(scip, conss[c]) )
11119	      {
11120	         *result = SCIP_INFEASIBLE;
11121	         maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
11122	
11123	         consdata = SCIPconsGetData(conss[c]);
11124	         assert(consdata != NULL);
11125	
11126	         /* print reason for infeasibility */
11127	         if( printreason )
11128	         {
11129	            SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11130	            SCIPinfoMessage(scip, NULL, ";\n");
11131	
11132	            if( consdata->lhsviol > SCIPfeastol(scip) )
11133	            {
11134	               SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11135	            }
11136	            if( consdata->rhsviol > SCIPfeastol(scip) )
11137	            {
11138	               SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11139	            }
11140	         }
11141	         else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11142	         {
11143	            /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11144	            return SCIP_OKAY;
11145	         }
11146	
11147	         /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11148	         if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
11149	            maypropfeasible = FALSE;
11150	
11151	         if( maypropfeasible )
11152	         {
11153	            if( consdata->lhsviol > SCIPfeastol(scip) )
11154	            {
11155	               /* check if there is a variable which may help to get the left hand side satisfied
11156	                * if there is no such variable, then we cannot get feasible
11157	                */
11158	               if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11159	                   !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11160	                  maypropfeasible = FALSE;
11161	            }
11162	            else
11163	            {
11164	               assert(consdata->rhsviol > SCIPfeastol(scip));
11165	               /* check if there is a variable which may help to get the right hand side satisfied
11166	                * if there is no such variable, then we cannot get feasible
11167	                */
11168	               if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11169	                   !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11170	                  maypropfeasible = FALSE;
11171	            }
11172	         }
11173	      }
11174	   }
11175	
11176	   if( *result == SCIP_INFEASIBLE && maypropfeasible )
11177	   {
11178	      SCIP_Bool success;
11179	
11180	      SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11181	
11182	      /* do not pass solution to NLP heuristic if we made it feasible this way */
11183	      if( success )
11184	         return SCIP_OKAY;
11185	   }
11186	
11187	   if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11188	   {
11189	      SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11190	   }
11191	
11192	   return SCIP_OKAY;
11193	}
11194	
11195	
11196	/** domain propagation method of constraint handler */
11197	static
11198	SCIP_DECL_CONSPROP(consPropNonlinear)
11199	{  /*lint --e{715}*/
11200	   int nchgbds = 0;
11201	
11202	   SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11203	   assert(nchgbds >= 0);
11204	
11205	   /* TODO would it make sense to check for redundant constraints? */
11206	
11207	   return SCIP_OKAY;
11208	}
11209	
11210	
11211	/** presolving method of constraint handler */
11212	static
11213	SCIP_DECL_CONSPRESOL(consPresolNonlinear)
11214	{  /*lint --e{715}*/
11215	   SCIP_CONSHDLRDATA* conshdlrdata;
11216	   SCIP_Bool infeasible;
11217	   int c;
11218	
11219	   *result = SCIP_DIDNOTFIND;
11220	
11221	   if( nconss == 0 )
11222	   {
11223	      *result = SCIP_DIDNOTRUN;
11224	      return SCIP_OKAY;
11225	   }
11226	
11227	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11228	   assert(conshdlrdata != NULL);
11229	
11230	   /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11231	   SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11232	   if( infeasible )
11233	   {
11234	      *result = SCIP_CUTOFF;
11235	      return SCIP_OKAY;
11236	   }
11237	
11238	   /* merge constraints with the same root expression */
11239	   if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11240	   {
11241	      SCIP_Bool success;
11242	
11243	      SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11244	      if( success )
11245	         *result = SCIP_SUCCESS;
11246	   }
11247	
11248	   /* propagate constraints */
11249	   SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11250	   if( *result == SCIP_CUTOFF )
11251	      return SCIP_OKAY;
11252	
11253	   /* propagate function domains (TODO integrate with simplify?) */
11254	   if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11255	   {
11256	      SCIP_RESULT localresult;
11257	      SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11258	      if( localresult == SCIP_CUTOFF )
11259	      {
11260	         *result = SCIP_CUTOFF;
11261	         return SCIP_OKAY;
11262	      }
11263	      if( localresult == SCIP_REDUCEDDOM )
11264	         *result = SCIP_REDUCEDDOM;
11265	   }
11266	
11267	   /* check for redundant constraints, remove constraints that are a value expression */
11268	   SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11269	   if( infeasible )
11270	   {
11271	      *result = SCIP_CUTOFF;
11272	      return SCIP_OKAY;
11273	   }
11274	
11275	   /* try to upgrade constraints */
11276	   for( c = 0; c < nconss; ++c )
11277	   {
11278	      SCIP_Bool upgraded;
11279	
11280	      /* skip inactive and deleted constraints */
11281	      if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11282	         continue;
11283	
11284	      SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11285	   }
11286	
11287	   /* try to change continuous variables that appear linearly to be implicit integer */
11288	   if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11289	   {
11290	      SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11291	
11292	      if( infeasible )
11293	      {
11294	         SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11295	         *result = SCIP_CUTOFF;
11296	         return SCIP_OKAY;
11297	      }
11298	   }
11299	
11300	   /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11301	   if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) && SCIPisPresolveFinished(scip)
11302	      && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11303	   {
11304	      /* run this presolving technique only once because we don't want to generate identical bound disjunction
11305	       * constraints multiple times
11306	       */
11307	      conshdlrdata->checkedvarlocks = TRUE;
11308	
11309	      for( c = 0; c < nconss; ++c )
11310	      {
11311	         int tmpnchgvartypes = 0;
11312	         int tmpnaddconss = 0;
11313	
11314	         SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11315	         SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11316	            SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11317	
11318	         if( infeasible )
11319	         {
11320	            SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11321	            *result = SCIP_CUTOFF;
11322	            return SCIP_OKAY;
11323	         }
11324	
11325	         (*nchgvartypes) += tmpnchgvartypes;
11326	         (*naddconss) += tmpnaddconss;
11327	      }
11328	   }
11329	
11330	   if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11331	      *result = SCIP_SUCCESS;
11332	   else
11333	      *result = SCIP_DIDNOTFIND;
11334	
11335	   return SCIP_OKAY;
11336	}
11337	
11338	
11339	/** propagation conflict resolving method of constraint handler */
11340	#ifdef SCIP_DISABLED_CODE
11341	static
11342	SCIP_DECL_CONSRESPROP(consRespropNonlinear)
11343	{  /*lint --e{715}*/
11344	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11345	   SCIPABORT(); /*lint --e{527}*/
11346	
11347	   return SCIP_OKAY;
11348	}
11349	#else
11350	#define consRespropNonlinear NULL
11351	#endif
11352	
11353	
11354	/** variable rounding lock method of constraint handler */
11355	static
11356	SCIP_DECL_CONSLOCK(consLockNonlinear)
11357	{  /*lint --e{715}*/
11358	   SCIP_CONSDATA* consdata;
11359	   SCIP_EXPR_OWNERDATA* ownerdata;
11360	   SCIP_Bool reinitsolve = FALSE;
11361	
11362	   assert(conshdlr != NULL);
11363	   assert(cons != NULL);
11364	
11365	   consdata = SCIPconsGetData(cons);
11366	   assert(consdata != NULL);
11367	   assert(consdata->expr != NULL);
11368	
11369	   ownerdata = SCIPexprGetOwnerData(consdata->expr);
11370	
11371	   /* check whether we need to initSolve again because
11372	    * - we have enfo initialized (nenfos >= 0)
11373	    * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11374	    */
11375	   if( ownerdata->nenfos >= 0 )
11376	   {
11377	      if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11378	         reinitsolve = TRUE;
11379	      if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11380	         reinitsolve = TRUE;
11381	   }
11382	
11383	   if( reinitsolve )
11384	   {
11385	      SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11386	   }
11387	
11388	   /* add locks */
11389	   SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11390	
11391	   if( reinitsolve )
11392	   {
11393	      SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11394	   }
11395	
11396	   return SCIP_OKAY;
11397	}
11398	
11399	
11400	/** constraint activation notification method of constraint handler */
11401	static
11402	SCIP_DECL_CONSACTIVE(consActiveNonlinear)
11403	{  /*lint --e{715}*/
11404	   SCIP_CONSDATA* consdata;
11405	   SCIP_Bool infeasible = FALSE;
11406	
11407	   consdata = SCIPconsGetData(cons);
11408	   assert(consdata != NULL);
11409	
11410	   /* simplify root expression if the constraint has been added after presolving */
11411	   if( SCIPgetStage(scip) > SCIP_STAGE_EXITPRESOLVE )
11412	   {
11413	      SCIP_Bool replacedroot;
11414	
11415	      if( !consdata->issimplified )
11416	      {
11417	         SCIP_EXPR* simplified;
11418	         SCIP_Bool changed;
11419	
11420	         /* simplify constraint */
11421	         SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11422	         SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11423	         assert(simplified != NULL);
11424	         consdata->expr = simplified;
11425	         consdata->issimplified = TRUE;
11426	      }
11427	
11428	      /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11429	      SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
11430	      assert(!replacedroot);  /* root expression cannot have been equal to one of its subexpressions */
11431	
11432	      /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11433	      {
11434	         SCIP_CONSHDLRDATA* conshdlrdata;
11435	         SCIP_EXPRITER* it;
11436	         SCIP_EXPR* expr;
11437	
11438	         conshdlrdata = SCIPconshdlrGetData(conshdlr);
11439	         assert(conshdlrdata != NULL);
11440	
11441	         SCIP_CALL( SCIPcreateExpriter(scip, &it) );
11442	         SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11443	         SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
11444	         for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
11445	         {
11446	            SCIP_EXPR* child;
11447	            SCIP_EXPR* hashmapexpr;
11448	
11449	            child = SCIPexpriterGetChildExprDFS(it);
11450	            if( !SCIPisExprVar(scip, child) )
11451	               continue;
11452	
11453	            /* check which expression is stored in the hashmap for the var of child */
11454	            hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11455	            /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11456	            if( hashmapexpr != NULL && hashmapexpr != child )
11457	            {
11458	               SCIP_CALL( SCIPreplaceExprChild(scip, expr, SCIPexpriterGetChildIdxDFS(it), hashmapexpr) );
11459	            }
11460	         }
11461	         SCIPfreeExpriter(&it);
11462	      }
11463	   }
11464	
11465	   /* store variable expressions */
11466	   if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
11467	   {
11468	      SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11469	   }
11470	
11471	   /* add manually locks to constraints that are not checked for feasibility */
11472	   if( !SCIPconsIsChecked(cons) )
11473	   {
11474	      assert(consdata->nlockspos == 0);
11475	      assert(consdata->nlocksneg == 0);
11476	
11477	      SCIP_CALL( addLocks(scip, cons, 1, 0) );
11478	   }
11479	
11480	   if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
11481	   {
11482	      SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11483	   }
11484	
11485	   /* TODO deal with infeasibility */
11486	   assert(!infeasible);
11487	
11488	   return SCIP_OKAY;
11489	}
11490	
11491	
11492	/** constraint deactivation notification method of constraint handler */
11493	static
11494	SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
11495	{  /*lint --e{715}*/
11496	   SCIP_CONSHDLRDATA* conshdlrdata;
11497	
11498	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11499	   assert(conshdlrdata != NULL);
11500	
11501	   if( SCIPgetStage(scip) < SCIP_STAGE_EXITSOLVE )
11502	   {
11503	      SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11504	   }
11505	
11506	   if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
11507	   {
11508	      SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11509	      SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(cons)) );
11510	   }
11511	
11512	   /* remove locks that have been added in consActiveExpr() */
11513	   if( !SCIPconsIsChecked(cons) )
11514	   {
11515	      SCIP_CALL( addLocks(scip, cons, -1, 0) );
11516	
11517	      assert(SCIPconsGetData(cons)->nlockspos == 0);
11518	      assert(SCIPconsGetData(cons)->nlocksneg == 0);
11519	   }
11520	
11521	   return SCIP_OKAY;
11522	}
11523	
11524	
11525	/** constraint enabling notification method of constraint handler */
11526	static
11527	SCIP_DECL_CONSENABLE(consEnableNonlinear)
11528	{  /*lint --e{715}*/
11529	   SCIP_CONSHDLRDATA* conshdlrdata;
11530	
11531	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11532	   assert(conshdlrdata != NULL);
11533	
11534	   if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
11535	   {
11536	      SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11537	   }
11538	
11539	   return SCIP_OKAY;
11540	}
11541	
11542	
11543	/** constraint disabling notification method of constraint handler */
11544	static
11545	SCIP_DECL_CONSDISABLE(consDisableNonlinear)
11546	{  /*lint --e{715}*/
11547	   SCIP_CONSHDLRDATA* conshdlrdata;
11548	
11549	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11550	   assert(conshdlrdata != NULL);
11551	
11552	   if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
11553	   {
11554	      SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11555	   }
11556	
11557	   return SCIP_OKAY;
11558	}
11559	
11560	/** variable deletion of constraint handler */
11561	#ifdef SCIP_DISABLED_CODE
11562	static
11563	SCIP_DECL_CONSDELVARS(consDelvarsNonlinear)
11564	{  /*lint --e{715}*/
11565	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11566	   SCIPABORT(); /*lint --e{527}*/
11567	
11568	   return SCIP_OKAY;
11569	}
11570	#else
11571	#define consDelvarsNonlinear NULL
11572	#endif
11573	
11574	
11575	/** constraint display method of constraint handler */
11576	static
11577	SCIP_DECL_CONSPRINT(consPrintNonlinear)
11578	{  /*lint --e{715}*/
11579	   SCIP_CONSDATA* consdata;
11580	
11581	   consdata = SCIPconsGetData(cons);
11582	   assert(consdata != NULL);
11583	   assert(consdata->expr != NULL);
11584	
11585	   /* print left hand side for ranged constraints */
11586	   if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11587	   {
11588	      SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
11589	   }
11590	
11591	   /* print expression */
11592	   SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
11593	
11594	   /* print right hand side */
11595	   if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11596	      SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
11597	   else if( !SCIPisInfinity(scip, consdata->rhs) )
11598	      SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
11599	   else if( !SCIPisInfinity(scip, -consdata->lhs) )
11600	      SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
11601	   else
11602	      SCIPinfoMessage(scip, file, " [free]");
11603	
11604	   return SCIP_OKAY;
11605	}
11606	
11607	
11608	/** constraint copying method of constraint handler */
11609	static
11610	SCIP_DECL_CONSCOPY(consCopyNonlinear)
11611	{  /*lint --e{715}*/
11612	   SCIP_CONSHDLR* targetconshdlr;
11613	   SCIP_EXPR* targetexpr = NULL;
11614	   SCIP_CONSDATA* sourcedata;
11615	
11616	   assert(cons != NULL);
11617	
11618	   sourcedata = SCIPconsGetData(sourcecons);
11619	   assert(sourcedata != NULL);
11620	
11621	   targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11622	   assert(targetconshdlr != NULL);
11623	
11624	   SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
11625	
11626	   if( targetexpr == NULL )
11627	      *valid = FALSE;
11628	
11629	   *cons = NULL;
11630	   if( *valid )
11631	   {
11632	      /* create copy (only capture targetexpr, no need to copy again) */
11633	      SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
11634	         targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11635	         initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11636	   }
11637	
11638	   if( targetexpr != NULL )
11639	   {
11640	      /* release target expr */
11641	      SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11642	   }
11643	
11644	   return SCIP_OKAY;
11645	}
11646	
11647	
11648	/** constraint parsing method of constraint handler */
11649	static
11650	SCIP_DECL_CONSPARSE(consParseNonlinear)
11651	{  /*lint --e{715}*/
11652	   SCIP_Real  lhs;
11653	   SCIP_Real  rhs;
11654	   char*      endptr;
11655	   SCIP_EXPR* consexprtree;
11656	
11657	   SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
11658	
11659	   assert(scip != NULL);
11660	   assert(success != NULL);
11661	   assert(str != NULL);
11662	   assert(name != NULL);
11663	   assert(cons != NULL);
11664	
11665	   *success = FALSE;
11666	
11667	   /* return if string empty */
11668	   if( !*str )
11669	      return SCIP_OKAY;
11670	
11671	   endptr = (char*)str;
11672	
11673	   /* set left and right hand side to their default values */
11674	   lhs = -SCIPinfinity(scip);
11675	   rhs =  SCIPinfinity(scip);
11676	
11677	   /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
11678	
11679	   /* check for left hand side */
11680	   if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
11681	   {
11682	      /* there is a number coming, maybe it is a left-hand-side */
11683	      if( !SCIPparseReal(scip, str, &lhs, &endptr) )
11684	      {
11685	         SCIPerrorMessage("error parsing number from <%s>\n", str);
11686	         return SCIP_READERROR;
11687	      }
11688	
11689	      /* ignore whitespace */
11690	      SCIP_CALL( SCIPskipSpace(&endptr) );
11691	
11692	      if( endptr[0] != '<' || endptr[1] != '=' )
11693	      {
11694	         /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
11695	         lhs = -SCIPinfinity(scip);
11696	      }
11697	      else
11698	      {
11699	         /* it was indeed a left-hand-side, so continue parsing after it */
11700	         str = endptr + 2;
11701	
11702	         /* ignore whitespace */
11703	         SCIP_CALL( SCIPskipSpace((char**)&str) );
11704	      }
11705	   }
11706	
11707	   SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
11708	
11709	   /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
11710	   SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
11711	
11712	   /* check for left or right hand side */
11713	   SCIP_CALL( SCIPskipSpace((char**)&str) );
11714	
11715	   /* check for free constraint */
11716	   if( strncmp(str, "[free]", 6) == 0 )
11717	   {
11718	      if( !SCIPisInfinity(scip, -lhs) )
11719	      {
11720	         SCIPerrorMessage("cannot have left hand side and [free] status \n");
11721	         SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
11722	         return SCIP_OKAY;
11723	      }
11724	      *success = TRUE;
11725	   }
11726	   else
11727	   {
11728	      switch( *str )
11729	      {
11730	         case '<':
11731	            *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
11732	            break;
11733	         case '=':
11734	            if( !SCIPisInfinity(scip, -lhs) )
11735	            {
11736	               SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
11737	               SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
11738	               return SCIP_OKAY;
11739	            }
11740	            else
11741	            {
11742	               *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
11743	               lhs = rhs;
11744	            }
11745	            break;
11746	         case '>':
11747	            if( !SCIPisInfinity(scip, -lhs) )
11748	            {
11749	               SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
11750	               SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
11751	               return SCIP_OKAY;
11752	            }
11753	            else
11754	            {
11755	               *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
11756	               break;
11757	            }
11758	         case '\0':
11759	            *success = TRUE;
11760	            break;
11761	         default:
11762	            SCIPerrorMessage("unexpected character %c\n", *str);
11763	            SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
11764	            return SCIP_OKAY;
11765	      }
11766	   }
11767	
11768	   /* create constraint */
11769	   SCIP_CALL( createCons(scip, conshdlr, cons, name,
11770	      consexprtree, lhs, rhs, FALSE,
11771	      initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11772	   assert(*cons != NULL);
11773	
11774	   SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
11775	
11776	   SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
11777	
11778	   return SCIP_OKAY;
11779	}
11780	
11781	
11782	/** constraint method of constraint handler which returns the variables (if possible) */
11783	static
11784	SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
11785	{  /*lint --e{715}*/
11786	   SCIP_CONSDATA* consdata;
11787	   int i;
11788	
11789	   consdata = SCIPconsGetData(cons);
11790	   assert(consdata != NULL);
11791	
11792	   /* store variable expressions if not done so far */
11793	   SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11794	
11795	   /* check whether array is too small in order to store all variables */
11796	   if( varssize < consdata->nvarexprs )
11797	   {
11798	      *success = FALSE;
11799	      return SCIP_OKAY;
11800	   }
11801	
11802	   for( i = 0; i < consdata->nvarexprs; ++i )
11803	   {
11804	      vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
11805	      assert(vars[i] != NULL);
11806	   }
11807	
11808	   *success = TRUE;
11809	
11810	   return SCIP_OKAY;
11811	}
11812	
11813	/** constraint method of constraint handler which returns the number of variables (if possible) */
11814	static
11815	SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
11816	{  /*lint --e{715}*/
11817	   SCIP_CONSDATA* consdata;
11818	
11819	   consdata = SCIPconsGetData(cons);
11820	   assert(consdata != NULL);
11821	
11822	   /* store variable expressions if not done so far */
11823	   SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11824	
11825	   *nvars = consdata->nvarexprs;
11826	   *success = TRUE;
11827	
11828	   return SCIP_OKAY;
11829	}
11830	
11831	/** constraint handler method to suggest dive bound changes during the generic diving algorithm */
11832	#ifdef SCIP_DISABLED_CODE
11833	static
11834	SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsNonlinear)
11835	{  /*lint --e{715}*/
11836	   SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11837	   SCIPABORT(); /*lint --e{527}*/
11838	
11839	   return SCIP_OKAY;
11840	}
11841	#else
11842	#define consGetDiveBdChgsNonlinear NULL
11843	#endif
11844	
11845	/** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
11846	static
11847	SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
11848	{  /*lint --e{715}*/
11849	   SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
11850	
11851	   return SCIP_OKAY;
11852	}
11853	
11854	/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
11855	static
11856	SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
11857	{  /*lint --e{715}*/
11858	   SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
11859	
11860	   return SCIP_OKAY;
11861	}
11862	
11863	/** output method of statistics table to output file stream 'file' */
11864	static
11865	SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
11866	{ /*lint --e{715}*/
11867	   SCIP_CONSHDLR* conshdlr;
11868	   SCIP_CONSHDLRDATA* conshdlrdata;
11869	
11870	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11871	   assert(conshdlr != NULL);
11872	
11873	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11874	   assert(conshdlrdata != NULL);
11875	
11876	   /* print statistics for constraint handler */
11877	   SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
11878	   SCIPinfoMessage(scip, file, "  enforce%-10s:", "");
11879	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
11880	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
11881	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
11882	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
11883	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
11884	   SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
11885	   SCIPinfoMessage(scip, file, "\n");
11886	   SCIPinfoMessage(scip, file, "  presolve%-9s: %-65s", "", "");
11887	   SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
11888	   SCIPinfoMessage(scip, file, "\n");
11889	
11890	   return SCIP_OKAY;
11891	}
11892	
11893	/** output method of statistics table to output file stream 'file' */
11894	static
11895	SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
11896	{ /*lint --e{715}*/
11897	   SCIP_CONSHDLR* conshdlr;
11898	   SCIP_CONSHDLRDATA* conshdlrdata;
11899	
11900	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11901	   assert(conshdlr != NULL);
11902	
11903	   /* skip nlhdlr table if there never were active nonlinear constraints */
11904	   if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
11905	      return SCIP_OKAY;
11906	
11907	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11908	   assert(conshdlrdata != NULL);
11909	
11910	   /* print statistics for nonlinear handlers */
11911	   SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
11912	
11913	   return SCIP_OKAY;
11914	}
11915	
11916	/** execution method of display nlhdlrs dialog */
11917	static
11918	SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
11919	{  /*lint --e{715}*/
11920	   SCIP_CONSHDLR* conshdlr;
11921	   SCIP_CONSHDLRDATA* conshdlrdata;
11922	   int i;
11923	
11924	   /* add dialog to history of dialogs that have been executed */
11925	   SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
11926	
11927	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11928	   assert(conshdlr != NULL);
11929	
11930	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
11931	   assert(conshdlrdata != NULL);
11932	
11933	   /* display list of nonlinear handler */
11934	   SCIPdialogMessage(scip, NULL, "\n");
11935	   SCIPdialogMessage(scip, NULL, " nonlinear handler  enabled  detectprio  enforceprio  description\n");
11936	   SCIPdialogMessage(scip, NULL, " -----------------  -------  ----------  -----------  -----------\n");
11937	   for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11938	   {
11939	      SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
11940	      assert(nlhdlr != NULL);
11941	
11942	      SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
11943	      SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
11944	      SCIPdialogMessage(scip, NULL, " %10d ", SCIPnlhdlrGetDetectPriority(nlhdlr));
11945	      SCIPdialogMessage(scip, NULL, " %11d ", SCIPnlhdlrGetEnfoPriority(nlhdlr));
11946	      SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
11947	      SCIPdialogMessage(scip, NULL, "\n");
11948	   }
11949	   SCIPdialogMessage(scip, NULL, "\n");
11950	
11951	   /* next dialog will be root dialog again */
11952	   *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
11953	
11954	   return SCIP_OKAY;
11955	}
11956	
11957	/*
11958	 * constraint handler specific interface methods
11959	 */
11960	
11961	/** creates the handler for nonlinear constraints and includes it in SCIP */
11962	SCIP_RETCODE SCIPincludeConshdlrNonlinear(
11963	   SCIP*                 scip                /**< SCIP data structure */
11964	   )
11965	{
11966	   SCIP_CONSHDLRDATA* conshdlrdata;
11967	   SCIP_DIALOG* parentdialog;
11968	
11969	   /* create nonlinear constraint handler data */
11970	   SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
11971	   conshdlrdata->intevalvar = intEvalVarBoundTightening;
11972	   conshdlrdata->curboundstag = 1;
11973	   conshdlrdata->lastboundrelax = 1;
11974	   conshdlrdata->curpropboundstag = 1;
11975	   conshdlrdata->newsoleventfilterpos = -1;
11976	   SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
11977	   SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
11978	   SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
11979	
11980	   /* include constraint handler */
11981	   SCIP_CALL( SCIPincludeConshdlr(scip, CONSHDLR_NAME, CONSHDLR_DESC,
11982	         CONSHDLR_SEPAPRIORITY, CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY,
11983	         CONSHDLR_SEPAFREQ, CONSHDLR_PROPFREQ, CONSHDLR_EAGERFREQ, CONSHDLR_MAXPREROUNDS,
11984	         CONSHDLR_DELAYSEPA, CONSHDLR_DELAYPROP, CONSHDLR_NEEDSCONS,
11985	         CONSHDLR_PROP_TIMING, CONSHDLR_PRESOLTIMING,
11986	         conshdlrCopyNonlinear,
11987	         consFreeNonlinear, consInitNonlinear, consExitNonlinear,
11988	         consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
11989	         consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
11990	         consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
11991	         consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
11992	         consActiveNonlinear, consDeactiveNonlinear,
11993	         consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
11994	         consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
11995	         consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
11996	         consGetSignedPermsymGraphNonlinear, conshdlrdata) );
11997	
11998	   /* add nonlinear constraint handler parameters */
11999	   /* TODO organize into more subcategories */
12000	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12001	         "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
12002	         &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12003	
12004	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12005	         "whether to check bounds of all auxiliary variable to seed reverse propagation",
12006	         &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12007	
12008	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12009	         "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",
12010	         &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12011	
12012	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12013	         "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12014	         &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12015	
12016	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12017	         "by how much to relax constraint sides during bound tightening",
12018	         &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12019	
12020	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12021	         "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12022	         &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12023	
12024	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12025	         "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12026	         &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12027	
12028	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12029	         "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12030	         &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12031	
12032	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12033	           "maximal number of auxiliary expressions per bilinear term",
12034	           &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12035	
12036	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12037	         "whether to reformulate products of binary variables during presolving",
12038	         &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12039	
12040	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12041	         "whether to use the AND constraint handler for reformulating binary products",
12042	         &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12043	
12044	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12045	         "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12046	         &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12047	
12048	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12049	         "whether to forbid multiaggregation of nonlinear variables",
12050	         &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12051	
12052	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12053	         "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12054	         &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12055	
12056	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12057	         "whether to (re)run propagation in enforcement",
12058	         &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12059	
12060	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12061	         "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12062	         &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12063	
12064	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12065	         "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12066	         &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12067	
12068	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12069	         "consider efficacy requirement when deciding whether a cut is \"strong\"",
12070	         &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12071	
12072	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12073	         "whether to force \"strong\" cuts in enforcement",
12074	         &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12075	
12076	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12077	         "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12078	         &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12079	
12080	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12081	         "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12082	         &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12083	
12084	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12085	         "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",
12086	         &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12087	
12088	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12089	         "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12090	         &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12091	
12092	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12093	         "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)",
12094	         &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12095	
12096	   SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12097	         "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12098	         &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12099	
12100	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12101	         "whether to use external branching candidates and branching rules for branching",
12102	         &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12103	
12104	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12105	         "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12106	         &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12107	
12108	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12109	         "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12110	         &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12111	
12112	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12113	         "weight by how much to consider the violation assigned to a variable for its branching score",
12114	         &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12115	
12116	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12117	         "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12118	         &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12119	
12120	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12121	         "weight by how much to consider the pseudo cost of a variable for its branching score",
12122	         &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12123	
12124	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12125	         "weight by how much to consider the domain width in branching score",
12126	         &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12127	
12128	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12129	         "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12130	         &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12131	
12132	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12133	         "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12134	         &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12135	
12136	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12137	         "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12138	         &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12139	
12140	   SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12141	         "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12142	         &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12143	
12144	   SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12145	         "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)",
12146	         &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12147	
12148	   SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12149	         "whether to assume that any constraint is convex",
12150	         &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
12151	
12152	   /* include handler for bound change events */
12153	   SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12154	         "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12155	   assert(conshdlrdata->eventhdlr != NULL);
12156	
12157	   /* include tables for statistics */
12158	   assert(SCIPfindTable(scip, TABLE_NAME_NONLINEAR) == NULL);
12159	   SCIP_CALL( SCIPincludeTable(scip, TABLE_NAME_NONLINEAR, TABLE_DESC_NONLINEAR, FALSE,
12160	         NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
12161	         NULL, TABLE_POSITION_NONLINEAR, TABLE_EARLIEST_STAGE_NONLINEAR) );
12162	
12163	   assert(SCIPfindTable(scip, TABLE_NAME_NLHDLR) == NULL);
12164	   SCIP_CALL( SCIPincludeTable(scip, TABLE_NAME_NLHDLR, TABLE_DESC_NLHDLR, TRUE,
12165	         NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
12166	         NULL, TABLE_POSITION_NLHDLR, TABLE_EARLIEST_STAGE_NLHDLR) );
12167	
12168	   /* create, include, and release display nlhdlrs dialog */
12169	   if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
12170	   {
12171	      SCIP_DIALOG* dialog;
12172	
12173	      assert(parentdialog != NULL);
12174	      assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
12175	
12176	      SCIP_CALL( SCIPincludeDialog(scip, &dialog,
12177	            NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
12178	            DIALOG_NAME, DIALOG_DESC, DIALOG_ISSUBMENU, NULL) );
12179	      SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
12180	      SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
12181	   }
12182	
12183	   SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12184	         processNewSolutionEvent, NULL) );
12185	
12186	   return SCIP_OKAY;
12187	}
12188	
12189	/** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12190	SCIP_RETCODE SCIPincludeConsUpgradeNonlinear(
12191	   SCIP*                 scip,               /**< SCIP data structure */
12192	   SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)),  /**< method to call for upgrading nonlinear constraint */
12193	   int                   priority,           /**< priority of upgrading method */
12194	   SCIP_Bool             active,             /**< should the upgrading method by active by default? */
12195	   const char*           conshdlrname        /**< name of the constraint handler */
12196	   )
12197	{
12198	   SCIP_CONSHDLR*     conshdlr;
12199	   SCIP_CONSHDLRDATA* conshdlrdata;
12200	   CONSUPGRADE*       consupgrade;
12201	   char               paramname[SCIP_MAXSTRLEN];
12202	   char               paramdesc[SCIP_MAXSTRLEN];
12203	   int                i;
12204	
12205	   assert(conshdlrname != NULL );
12206	   assert(nlconsupgd != NULL);
12207	
12208	   /* find the nonlinear constraint handler */
12209	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12210	   if( conshdlr == NULL )
12211	   {
12212	      SCIPerrorMessage("nonlinear constraint handler not found\n");
12213	      return SCIP_PLUGINNOTFOUND;
12214	   }
12215	
12216	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12217	   assert(conshdlrdata != NULL);
12218	
12219	   /* check whether upgrade method exists already */
12220	   for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12221	   {
12222	      if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12223	      {
12224	#ifdef SCIP_DEBUG
12225	         SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12226	#endif
12227	         return SCIP_OKAY;
12228	      }
12229	   }
12230	
12231	   /* create a nonlinear constraint upgrade data object */
12232	   SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
12233	   consupgrade->consupgd = nlconsupgd;
12234	   consupgrade->priority = priority;
12235	   consupgrade->active   = active;
12236	
12237	   /* insert nonlinear constraint upgrade method into constraint handler data */
12238	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12239	   assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12240	
12241	   for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12242	      conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12243	   assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12244	   conshdlrdata->consupgrades[i] = consupgrade;
12245	   conshdlrdata->nconsupgrades++;
12246	
12247	   /* adds parameter to turn on and off the upgrading step */
12248	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12249	   (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12250	   SCIP_CALL( SCIPaddBoolParam(scip,
12251	         paramname, paramdesc,
12252	         &consupgrade->active, FALSE, active, NULL, NULL) );
12253	
12254	   return SCIP_OKAY;
12255	}
12256	
12257	/** creates and captures a nonlinear constraint
12258	 *
12259	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12260	 */
12261	SCIP_RETCODE SCIPcreateConsNonlinear(
12262	   SCIP*                 scip,               /**< SCIP data structure */
12263	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
12264	   const char*           name,               /**< name of constraint */
12265	   SCIP_EXPR*            expr,               /**< expression of constraint (must not be NULL) */
12266	   SCIP_Real             lhs,                /**< left hand side of constraint */
12267	   SCIP_Real             rhs,                /**< right hand side of constraint */
12268	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
12269	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12270	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
12271	                                              *   Usually set to TRUE. */
12272	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
12273	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
12274	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
12275	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
12276	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
12277	                                              *   Usually set to TRUE. */
12278	   SCIP_Bool             local,              /**< is constraint only valid locally?
12279	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12280	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
12281	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
12282	                                              *   adds coefficients to this constraint. */
12283	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
12284	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
12285	                                              *   are separated as constraints. */
12286	   SCIP_Bool             removable           /**< should the relaxation be removed from the LP due to aging or cleanup?
12287	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12288	   )
12289	{
12290	   /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12291	   SCIP_CONSHDLR* conshdlr;
12292	
12293	   /* find the nonlinear constraint handler */
12294	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12295	   if( conshdlr == NULL )
12296	   {
12297	      SCIPerrorMessage("nonlinear constraint handler not found\n");
12298	      return SCIP_PLUGINNOTFOUND;
12299	   }
12300	
12301	   /* create constraint */
12302	   SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12303	      initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12304	
12305	   return SCIP_OKAY;
12306	}
12307	
12308	/** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12309	 *
12310	 *  All flags can be set via SCIPconsSetFLAGNAME-methods.
12311	 *
12312	 *  @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12313	 *
12314	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12315	 */
12316	SCIP_RETCODE SCIPcreateConsBasicNonlinear(
12317	   SCIP*                 scip,               /**< SCIP data structure */
12318	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
12319	   const char*           name,               /**< name of constraint */
12320	   SCIP_EXPR*            expr,               /**< expression of constraint (must not be NULL) */
12321	   SCIP_Real             lhs,                /**< left hand side of constraint */
12322	   SCIP_Real             rhs                 /**< right hand side of constraint */
12323	   )
12324	{
12325	   SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12326	         TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
12327	
12328	   return SCIP_OKAY;
12329	}
12330	
12331	/** creates and captures a quadratic nonlinear constraint
12332	 *
12333	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12334	 */
12335	SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(
12336	   SCIP*                 scip,               /**< SCIP data structure */
12337	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
12338	   const char*           name,               /**< name of constraint */
12339	   int                   nlinvars,           /**< number of linear terms */
12340	   SCIP_VAR**            linvars,            /**< array with variables in linear part */
12341	   SCIP_Real*            lincoefs,           /**< array with coefficients of variables in linear part */
12342	   int                   nquadterms,         /**< number of quadratic terms */
12343	   SCIP_VAR**            quadvars1,          /**< array with first variables in quadratic terms */
12344	   SCIP_VAR**            quadvars2,          /**< array with second variables in quadratic terms */
12345	   SCIP_Real*            quadcoefs,          /**< array with coefficients of quadratic terms */
12346	   SCIP_Real             lhs,                /**< left hand side of quadratic equation */
12347	   SCIP_Real             rhs,                /**< right hand side of quadratic equation */
12348	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
12349	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12350	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
12351	                                              *   Usually set to TRUE. */
12352	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
12353	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
12354	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
12355	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
12356	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
12357	                                              *   Usually set to TRUE. */
12358	   SCIP_Bool             local,              /**< is constraint only valid locally?
12359	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12360	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
12361	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
12362	                                              *   adds coefficients to this constraint. */
12363	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
12364	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
12365	                                              *   are separated as constraints. */
12366	   SCIP_Bool             removable           /**< should the relaxation be removed from the LP due to aging or cleanup?
12367	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12368	   )
12369	{
12370	   SCIP_CONSHDLR* conshdlr;
12371	   SCIP_EXPR* expr;
12372	
12373	   assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12374	   assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12375	
12376	   /* get nonlinear constraint handler */
12377	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12378	   if( conshdlr == NULL )
12379	   {
12380	      SCIPerrorMessage("nonlinear constraint handler not found\n");
12381	      return SCIP_PLUGINNOTFOUND;
12382	   }
12383	
12384	   /* create quadratic expression */
12385	   SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12386	   assert(expr != NULL);
12387	
12388	   /* create nonlinear constraint */
12389	   SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
12390	      initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12391	
12392	   /* release quadratic expression (captured by constraint now) */
12393	   SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12394	
12395	   return SCIP_OKAY;
12396	}
12397	
12398	/** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
12399	 *
12400	 *  All flags can be set via SCIPconsSetFLAGNAME-methods.
12401	 *
12402	 *  @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
12403	 *
12404	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12405	 */
12406	SCIP_RETCODE SCIPcreateConsBasicQuadraticNonlinear(
12407	   SCIP*                 scip,               /**< SCIP data structure */
12408	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
12409	   const char*           name,               /**< name of constraint */
12410	   int                   nlinvars,           /**< number of linear terms */
12411	   SCIP_VAR**            linvars,            /**< array with variables in linear part */
12412	   SCIP_Real*            lincoefs,           /**< array with coefficients of variables in linear part */
12413	   int                   nquadterms,         /**< number of quadratic terms */
12414	   SCIP_VAR**            quadvars1,          /**< array with first variables in quadratic terms */
12415	   SCIP_VAR**            quadvars2,          /**< array with second variables in quadratic terms */
12416	   SCIP_Real*            quadcoefs,          /**< array with coefficients of quadratic terms */
12417	   SCIP_Real             lhs,                /**< left hand side of quadratic equation */
12418	   SCIP_Real             rhs                 /**< right hand side of quadratic equation */
12419	   )
12420	{
12421	   SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
12422	      TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
12423	
12424	   return SCIP_OKAY;
12425	}
12426	
12427	/** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
12428	 *
12429	 * \f$\sqrt{\gamma + \sum_{i=1}^{n} (\alpha_i\, (x_i + \beta_i))^2} \leq \alpha_{n+1}\, (x_{n+1}+\beta_{n+1})\f$
12430	 *
12431	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12432	 */
12433	SCIP_RETCODE SCIPcreateConsBasicSOCNonlinear(
12434	   SCIP*                 scip,               /**< SCIP data structure */
12435	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
12436	   const char*           name,               /**< name of constraint */
12437	   int                   nvars,              /**< number of variables on left hand side of constraint (n) */
12438	   SCIP_VAR**            vars,               /**< array with variables on left hand side (x_i) */
12439	   SCIP_Real*            coefs,              /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
12440	   SCIP_Real*            offsets,            /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
12441	   SCIP_Real             constant,           /**< constant on left hand side (gamma) */
12442	   SCIP_VAR*             rhsvar,             /**< variable on right hand side of constraint (x_{n+1}) */
12443	   SCIP_Real             rhscoeff,           /**< coefficient of variable on right hand side (alpha_{n+1}) */
12444	   SCIP_Real             rhsoffset           /**< offset of variable on right hand side (beta_{n+1}) */
12445	   )
12446	{
12447	   SCIP_EXPR* expr;
12448	   SCIP_EXPR* lhssum;
12449	   SCIP_EXPR* terms[2];
12450	   SCIP_Real termcoefs[2];
12451	   int i;
12452	
12453	   assert(vars != NULL || nvars == 0);
12454	
12455	   SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) );  /* gamma */
12456	   for( i = 0; i < nvars; ++i )
12457	   {
12458	      SCIP_EXPR* varexpr;
12459	      SCIP_EXPR* powexpr;
12460	
12461	      SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) );   /* x_i */
12462	      if( offsets != NULL && offsets[i] != 0.0 )
12463	      {
12464	         SCIP_EXPR* sum;
12465	         SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) );  /* x_i + beta_i */
12466	         SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) );   /* (x_i + beta_i)^2 */
12467	         SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
12468	      }
12469	      else
12470	      {
12471	         SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) );  /* x_i^2 */
12472	      }
12473	
12474	      SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) );  /* + alpha_i^2 (x_i + beta_i)^2 */
12475	      SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12476	      SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
12477	   }
12478	
12479	   SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) );  /* sqrt(...) */
12480	   SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
12481	   termcoefs[0] = 1.0;
12482	
12483	   SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) );  /* x_{n+1} */
12484	   termcoefs[1] = -rhscoeff;
12485	
12486	   SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) );  /* sqrt(...) - alpha_{n+1}x_{n_1} */
12487	
12488	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12489	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12490	
12491	   SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
12492	
12493	   SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12494	
12495	   return SCIP_OKAY;
12496	}
12497	
12498	/** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
12499	 *
12500	 * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
12501	 *
12502	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12503	 */
12504	SCIP_RETCODE SCIPcreateConsBasicSignpowerNonlinear(
12505	   SCIP*                 scip,               /**< SCIP data structure */
12506	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
12507	   const char*           name,               /**< name of constraint */
12508	   SCIP_VAR*             x,                  /**< nonlinear variable x in constraint */
12509	   SCIP_VAR*             z,                  /**< linear variable z in constraint */
12510	   SCIP_Real             exponent,           /**< exponent n of |x+offset|^n term in constraint */
12511	   SCIP_Real             xoffset,            /**< offset in |x+offset|^n term in constraint */
12512	   SCIP_Real             zcoef,              /**< coefficient of z in constraint */
12513	   SCIP_Real             lhs,                /**< left hand side of constraint */
12514	   SCIP_Real             rhs                 /**< right hand side of constraint */
12515	   )
12516	{
12517	   SCIP_EXPR* xexpr;
12518	   SCIP_EXPR* terms[2];
12519	   SCIP_Real coefs[2];
12520	   SCIP_EXPR* sumexpr;
12521	
12522	   assert(x != NULL);
12523	   assert(z != NULL);
12524	
12525	   SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
12526	   if( xoffset != 0.0 )
12527	   {
12528	      SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
12529	      SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
12530	
12531	      SCIP_CALL( SCIPreleaseExpr(scip,  &sumexpr) );
12532	   }
12533	   else
12534	   {
12535	      SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) );  /* signpow(x, exponent) */
12536	   }
12537	   coefs[0] = 1.0;
12538	
12539	   SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
12540	   coefs[1] = zcoef;
12541	
12542	   SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) );  /* signpowexpr + zcoef * z */
12543	
12544	   SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
12545	
12546	   SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
12547	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12548	   SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12549	   SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
12550	
12551	   return SCIP_OKAY;
12552	}
12553	
12554	/** gets tag indicating current local variable bounds */
12555	SCIP_Longint SCIPgetCurBoundsTagNonlinear(
12556	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
12557	   )
12558	{
12559	   SCIP_CONSHDLRDATA* conshdlrdata;
12560	
12561	   assert(conshdlr != NULL);
12562	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12563	
12564	   return conshdlrdata->curboundstag;
12565	}
12566	
12567	/** gets the `curboundstag` from the last time where variable bounds were relaxed */
12568	SCIP_Longint SCIPgetLastBoundRelaxTagNonlinear(
12569	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
12570	   )
12571	{
12572	   SCIP_CONSHDLRDATA* conshdlrdata;
12573	
12574	   assert(conshdlr != NULL);
12575	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12576	
12577	   return conshdlrdata->lastboundrelax;
12578	}
12579	
12580	/** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
12581	 *
12582	 * @attention This method is not intended for normal use.
12583	 *   These tags are maintained by the event handler for variable bound change events.
12584	 *   This method is used by some unittests.
12585	 */
12586	void SCIPincrementCurBoundsTagNonlinear(
12587	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
12588	   SCIP_Bool             boundrelax          /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
12589	   )
12590	{
12591	   SCIP_CONSHDLRDATA* conshdlrdata;
12592	
12593	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12594	   assert(conshdlrdata != NULL);
12595	
12596	   ++conshdlrdata->curboundstag;
12597	   assert(conshdlrdata->curboundstag > 0);
12598	
12599	   if( boundrelax )
12600	      conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
12601	}
12602	
12603	/** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
12604	SCIP_HASHMAP* SCIPgetVarExprHashmapNonlinear(
12605	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
12606	   )
12607	{
12608	   assert(conshdlr != NULL);
12609	
12610	   return SCIPconshdlrGetData(conshdlr)->var2expr;
12611	}
12612	
12613	/** processes a rowprep for cut addition and maybe report branchscores */
12614	SCIP_RETCODE SCIPprocessRowprepNonlinear(
12615	   SCIP*                 scip,               /**< SCIP data structure */
12616	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler which provided the estimator */
12617	   SCIP_CONS*            cons,               /**< nonlinear constraint */
12618	   SCIP_EXPR*            expr,               /**< expression */
12619	   SCIP_ROWPREP*         rowprep,            /**< cut to be added */
12620	   SCIP_Bool             overestimate,       /**< whether the expression needs to be over- or underestimated */
12621	   SCIP_VAR*             auxvar,             /**< auxiliary variable */
12622	   SCIP_Real             auxvalue,           /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
12623	   SCIP_Bool             allowweakcuts,      /**< whether we should only look for "strong" cuts, or anything that separates is fine */
12624	   SCIP_Bool             branchscoresuccess, /**< whether the estimator generation generated branching scores */
12625	   SCIP_Bool             inenforcement,      /**< whether we are in enforcement, or only in separation */
12626	   SCIP_SOL*             sol,                /**< solution to be separated (NULL for the LP solution) */
12627	   SCIP_RESULT*          result              /**< pointer to store the result */
12628	   )
12629	{
12630	   SCIP_Real cutviol;
12631	   SCIP_CONSHDLRDATA* conshdlrdata;
12632	   SCIP_Real auxvarvalue = SCIP_INVALID;
12633	   SCIP_Bool sepasuccess;
12634	   SCIP_Real estimateval = SCIP_INVALID;
12635	   SCIP_Real mincutviolation;
12636	
12637	   assert(nlhdlr != NULL);
12638	   assert(cons != NULL);
12639	   assert(expr != NULL);
12640	   assert(rowprep != NULL);
12641	   assert(auxvar != NULL);
12642	   assert(result != NULL);
12643	
12644	   /* decide on minimal violation of cut */
12645	   if( sol == NULL )
12646	      mincutviolation = SCIPgetLPFeastol(scip);  /* we enforce an LP solution */
12647	   else
12648	      mincutviolation = SCIPfeastol(scip);
12649	
12650	   conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
12651	   assert(conshdlrdata != NULL);
12652	
12653	   sepasuccess = TRUE;
12654	
12655	   cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
12656	   if( cutviol > 0.0 )
12657	   {
12658	      auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
12659	
12660	      /* check whether cut is weak (if f(x) not defined, then it's never weak) */
12661	      if( !allowweakcuts && auxvalue != SCIP_INVALID )
12662	      {
12663	         /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
12664	          * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
12665	          * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
12666	          * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
12667	          * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
12668	          *   <->   c'x-b - z <= weakcutthreshold * (f(x)-z)
12669	          *
12670	          * if we are overestimating, we have z >= c'x-b >= f(x)
12671	          * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
12672	          * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
12673	          *   <->   c'x-b - z >= weakcutthreshold * (f(x)-z)
12674	          *
12675	          * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
12676	          */
12677	         if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
12678	             ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
12679	         {
12680	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s succeeded, but cut is too "\
12681	                           "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
12682	                                     SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
12683	                                     auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
12684	            sepasuccess = FALSE;
12685	         }
12686	      }
12687	
12688	      /* save estimator value for later, see long comment above why this gives the value for c'x-b */
12689	      estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
12690	   }
12691	   else
12692	   {
12693	      sepasuccess = FALSE;
12694	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s succeeded, but cut does not "\
12695	                     "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
12696	   }
12697	
12698	   /* clean up estimator */
12699	   if( sepasuccess )
12700	   {
12701	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    estimate of nlhdlr %s succeeded: auxvarvalue %g "\
12702	                     "estimateval %g auxvalue %g (over %d)\n    ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
12703	                               auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
12704	                       SCIPprintRowprep(scip, rowprep, enfologfile); )
12705	
12706	      /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
12707	       * instead, may even scale them down, that is, scale so that max coef is close to 1
12708	       */
12709	      if( !allowweakcuts )
12710	      {
12711	         SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
12712	
12713	         if( !sepasuccess )
12714	         {
12715	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cleanup cut failed due to bad numerics\n"); )
12716	         }
12717	         else
12718	         {
12719	            cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
12720	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cleanup succeeded, violation = %g and %sreliable, "\
12721	                           "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
12722	            if( sepasuccess )
12723	               sepasuccess = cutviol > mincutviolation;
12724	         }
12725	
12726	         if( sepasuccess && auxvalue != SCIP_INVALID )
12727	         {
12728	            /* check whether cut is weak now
12729	             * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
12730	             * reconstructing estimateval from cutviol (TODO improve or remove?)
12731	             */
12732	            SCIP_Real auxvarcoef = 0.0;
12733	            int i;
12734	
12735	            /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
12736	             * it should be...
12737	             */
12738	            for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
12739	            {
12740	               if( SCIProwprepGetVars(rowprep)[i] == auxvar )
12741	               {
12742	                  auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
12743	                  break;
12744	               }
12745	            }
12746	
12747	            if( auxvarcoef == 0.0 ||
12748	                (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
12749	                ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
12750	            {
12751	               ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
12752	                  auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
12753	               sepasuccess = FALSE;
12754	            }
12755	         }
12756	      }
12757	      else
12758	      {
12759	         /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
12760	
12761	         /* if estimate didn't report branchscores explicitly, then consider branching on those children for
12762	          * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
12763	          */
12764	         if( !branchscoresuccess )
12765	            SCIProwprepRecordModifications(rowprep);
12766	
12767	         SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
12768	
12769	         if( !sepasuccess )
12770	         {
12771	            ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cleanup failed, %d coefs modified, cutviol %g\n",
12772	                                     SCIProwprepGetNModifiedVars(rowprep), cutviol); )
12773	         }
12774	
12775	         /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
12776	          * changed
12777	          */
12778	         if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
12779	         {
12780	            SCIP_Real violscore;
12781	
12782	#ifdef BRSCORE_ABSVIOL
12783	            violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
12784	#else
12785	            SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
12786	#endif
12787	            SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
12788	
12789	            /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
12790	             * - were fixed,
12791	             * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
12792	             * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
12793	             * the first case came up again in #3085 and I don't see how to exclude this in the assert,
12794	             * so I'm disabling the assert for now
12795	             */
12796	            /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
12797	                  strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
12798	         }
12799	      }
12800	   }
12801	
12802	   /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
12803	   if( sepasuccess )
12804	   {
12805	      SCIP_ROW* row;
12806	
12807	      if( conshdlrdata->branchdualweight > 0.0 )
12808	      {
12809	         /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
12810	          * skip if gap is zero
12811	          */
12812	         if( auxvalue == SCIP_INVALID )
12813	            strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
12814	         else if( !SCIPisEQ(scip, auxvalue, estimateval) )
12815	         {
12816	            char gap[40];
12817	            (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
12818	            strcat(SCIProwprepGetName(rowprep), gap);
12819	         }
12820	      }
12821	
12822	      SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
12823	
12824	      if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
12825	      {
12826	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cut efficacy %g is too low (minefficacy=%g)\n",
12827	                                  SCIPgetCutEfficacy(scip, sol, row), SCIPgetSepaMinEfficacy(scip)); )
12828	      }
12829	      else if( !SCIPisCutApplicable(scip, row) )
12830	      {
12831	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    cut not applicable (e.g., cut is boundchange below eps)\n"); )
12832	      }
12833	      else
12834	      {
12835	         SCIP_Bool infeasible;
12836	
12837	         ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    adding cut ");
12838	           SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
12839	
12840	         /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
12841	          * if we haven't found strong cuts before)
12842	          */
12843	         SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
12844	
12845	         /* mark row as not removable from LP for current node (this can prevent some cycling) */
12846	         if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
12847	            SCIPmarkRowNotRemovableLocal(scip, row);
12848	
12849	         if( infeasible )
12850	         {
12851	            *result = SCIP_CUTOFF;
12852	            SCIPnlhdlrIncrementNCutoffs(nlhdlr);
12853	         }
12854	         else
12855	         {
12856	            *result = SCIP_SEPARATED;
12857	            SCIPnlhdlrIncrementNSeparated(nlhdlr);
12858	         }
12859	      }
12860	
12861	      SCIP_CALL( SCIPreleaseRow(scip, &row) );
12862	   }
12863	   else if( branchscoresuccess )
12864	   {
12865	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    separation with estimate of nlhdlr %s failed, but "\
12866	                     "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
12867	
12868	      /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
12869	       * expressions eligible for branching candidate, see enforceConstraints() and branching()
12870	       */
12871	      *result = SCIP_BRANCHED;
12872	   }
12873	   else
12874	   {
12875	      ENFOLOG( SCIPinfoMessage(scip, enfologfile, "    separation with estimate of nlhdlr %s failed and no "\
12876	                     "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
12877	                                                                                    " (!)" : ""); )
12878	   }
12879	
12880	   return SCIP_OKAY;
12881	}
12882	
12883	/** returns whether all nonlinear constraints are assumed to be convex */
12884	SCIP_Bool SCIPassumeConvexNonlinear(
12885	   SCIP_CONSHDLR*        conshdlr
12886	   )
12887	{
12888	   SCIP_CONSHDLRDATA* conshdlrdata;
12889	
12890	   assert(conshdlr != NULL);
12891	
12892	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12893	   assert(conshdlrdata != NULL);
12894	
12895	   return conshdlrdata->assumeconvex;
12896	}
12897	
12898	/** collects all bilinear terms for a given set of constraints
12899	 *
12900	 * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
12901	 *       SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
12902	 */
12903	SCIP_RETCODE SCIPcollectBilinTermsNonlinear(
12904	   SCIP*                 scip,               /**< SCIP data structure */
12905	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
12906	   SCIP_CONS**           conss,              /**< nonlinear constraints */
12907	   int                   nconss              /**< total number of nonlinear constraints */
12908	   )
12909	{
12910	   assert(conshdlr != NULL);
12911	   assert(conss != NULL || nconss == 0);
12912	
12913	   SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
12914	
12915	   return SCIP_OKAY;
12916	}
12917	
12918	/** returns the total number of bilinear terms that are contained in all nonlinear constraints
12919	 *
12920	 *  @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
12921	 */
12922	int SCIPgetNBilinTermsNonlinear(
12923	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
12924	   )
12925	{
12926	   SCIP_CONSHDLRDATA* conshdlrdata;
12927	
12928	   assert(conshdlr != NULL);
12929	
12930	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12931	   assert(conshdlrdata != NULL);
12932	
12933	   return conshdlrdata->nbilinterms;
12934	}
12935	
12936	/** returns all bilinear terms that are contained in all nonlinear constraints
12937	 *
12938	 * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
12939	 * @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.
12940	 */
12941	SCIP_CONSNONLINEAR_BILINTERM* SCIPgetBilinTermsNonlinear(
12942	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
12943	   )
12944	{
12945	   SCIP_CONSHDLRDATA* conshdlrdata;
12946	
12947	   assert(conshdlr != NULL);
12948	
12949	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12950	   assert(conshdlrdata != NULL);
12951	
12952	   return conshdlrdata->bilinterms;
12953	}
12954	
12955	/** returns the index of the bilinear term representing the product of the two given variables
12956	 *
12957	 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
12958	 * @return The method returns -1 if the variables do not appear bilinearly.
12959	 */
12960	int SCIPgetBilinTermIdxNonlinear(
12961	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
12962	   SCIP_VAR*             x,                  /**< first variable */
12963	   SCIP_VAR*             y                   /**< second variable */
12964	   )
12965	{
12966	   SCIP_CONSHDLRDATA* conshdlrdata;
12967	   SCIP_CONSNONLINEAR_BILINTERM entry;
12968	   int idx;
12969	
12970	   assert(conshdlr != NULL);
12971	   assert(x != NULL);
12972	   assert(y != NULL);
12973	
12974	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12975	   assert(conshdlrdata != NULL);
12976	
12977	   if( conshdlrdata->bilinhashtable == NULL )
12978	   {
12979	      return -1;
12980	   }
12981	
12982	   /* ensure that x.index <= y.index */
12983	   if( SCIPvarCompare(x, y) == 1 )
12984	   {
12985	      SCIPswapPointers((void**)&x, (void**)&y);
12986	   }
12987	   assert(SCIPvarCompare(x, y) < 1);
12988	
12989	   /* use a new entry to find the image in the bilinear hash table */
12990	   entry.x = x;
12991	   entry.y = y;
12992	   idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
12993	   assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
12994	   assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
12995	   assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
12996	
12997	   return idx;
12998	}
12999	
13000	/** returns the bilinear term that represents the product of two given variables
13001	 *
13002	 * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13003	 * @return The method returns NULL if the variables do not appear bilinearly.
13004	 */
13005	SCIP_CONSNONLINEAR_BILINTERM* SCIPgetBilinTermNonlinear(
13006	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
13007	   SCIP_VAR*             x,                  /**< first variable */
13008	   SCIP_VAR*             y                   /**< second variable */
13009	   )
13010	{
13011	   SCIP_CONSHDLRDATA* conshdlrdata;
13012	   int idx;
13013	
13014	   assert(conshdlr != NULL);
13015	   assert(x != NULL);
13016	   assert(y != NULL);
13017	
13018	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13019	   assert(conshdlrdata != NULL);
13020	
13021	   idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13022	   assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13023	
13024	   if( idx >= 0 )
13025	   {
13026	      return &conshdlrdata->bilinterms[idx];
13027	   }
13028	
13029	   return NULL;
13030	}
13031	
13032	/** evaluates an auxiliary expression for a bilinear term */
13033	SCIP_Real SCIPevalBilinAuxExprNonlinear(
13034	   SCIP*                 scip,               /**< SCIP data structure */
13035	   SCIP_VAR*             x,                  /**< first variable of the bilinear term */
13036	   SCIP_VAR*             y,                  /**< second variable of the bilinear term */
13037	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr,      /**< auxiliary expression */
13038	   SCIP_SOL*             sol                 /**< solution at which to evaluate (can be NULL) */
13039	   )
13040	{
13041	   assert(scip != NULL);
13042	   assert(x != NULL);
13043	   assert(y != NULL);
13044	   assert(auxexpr != NULL);
13045	   assert(auxexpr->auxvar != NULL);
13046	
13047	   return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13048	          auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13049	}
13050	
13051	/** stores the variables of a bilinear term in the data of the constraint handler */
13052	SCIP_RETCODE SCIPinsertBilinearTermExistingNonlinear(
13053	   SCIP*                 scip,               /**< SCIP data structure */
13054	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
13055	   SCIP_VAR*             x,                  /**< first variable */
13056	   SCIP_VAR*             y,                  /**< second variable */
13057	   SCIP_VAR*             auxvar,             /**< auxiliary variable (might be NULL) */
13058	   int                   nlockspos,          /**< number of positive expression locks */
13059	   int                   nlocksneg           /**< number of negative expression locks */
13060	   )
13061	{
13062	   SCIP_CONSHDLRDATA* conshdlrdata;
13063	   SCIP_CONSNONLINEAR_BILINTERM* term;
13064	   int idx;
13065	
13066	   assert(conshdlr != NULL);
13067	
13068	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13069	   assert(conshdlrdata != NULL);
13070	
13071	   SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13072	
13073	   term = &conshdlrdata->bilinterms[idx];
13074	   assert(term != NULL);
13075	   assert(term->nauxexprs == 0);  /* existing terms should be added before implicit terms */
13076	   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) */
13077	
13078	   /* store and capture auxiliary variable */
13079	   if( auxvar != NULL )
13080	   {
13081	      term->aux.var = auxvar;
13082	      SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13083	   }
13084	
13085	   return SCIP_OKAY;
13086	}
13087	
13088	/** stores the variables of a bilinear term in the data of the constraint handler */
13089	SCIP_RETCODE SCIPinsertBilinearTermImplicitNonlinear(
13090	   SCIP*                 scip,               /**< SCIP data structure */
13091	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
13092	   SCIP_VAR*             x,                  /**< first variable */
13093	   SCIP_VAR*             y,                  /**< second variable */
13094	   SCIP_VAR*             auxvar,             /**< auxiliary variable (might be NULL) */
13095	   SCIP_Real             coefx,              /**< coefficient of x in the auxiliary expression */
13096	   SCIP_Real             coefy,              /**< coefficient of y in the auxiliary expression */
13097	   SCIP_Real             coefaux,            /**< coefficient of auxvar in the auxiliary expression */
13098	   SCIP_Real             cst,                /**< constant of the auxiliary expression */
13099	   SCIP_Bool             overestimate        /**< whether the auxiliary expression overestimates the bilinear product */
13100	   )
13101	{
13102	   SCIP_CONSHDLRDATA* conshdlrdata;
13103	   SCIP_CONSNONLINEAR_BILINTERM* term;
13104	   SCIP_CONSNONLINEAR_AUXEXPR* auxexpr;
13105	   int idx;
13106	   int nlockspos;
13107	   int nlocksneg;
13108	   SCIP_Bool added;
13109	
13110	   assert(conshdlr != NULL);
13111	
13112	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13113	   assert(conshdlrdata != NULL);
13114	
13115	   nlockspos = overestimate ? 1 : 0;
13116	   nlocksneg = overestimate ? 0 : 1;
13117	
13118	   SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13119	
13120	   term = &conshdlrdata->bilinterms[idx];
13121	   assert(term != NULL);
13122	   assert(SCIPvarCompare(term->x, term->y) < 1);
13123	
13124	   if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13125	   {
13126	      SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
13127	      /* this is the case where we are adding an implicitly defined relation for a product that has already
13128	       * been explicitly defined; convert auxvar into an auxexpr */
13129	
13130	      /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13131	      if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13132	         return SCIP_OKAY;
13133	
13134	      SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
13135	      auxvarexpr->cst = 0.0;
13136	      auxvarexpr->coefs[0] = 1.0;
13137	      auxvarexpr->coefs[1] = 0.0;
13138	      auxvarexpr->coefs[2] = 0.0;
13139	      auxvarexpr->auxvar = term->aux.var;
13140	      auxvarexpr->underestimate = term->nlocksneg > 0;
13141	      auxvarexpr->overestimate = term->nlockspos > 0;
13142	
13143	      /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13144	      term->aux.exprs = NULL;
13145	
13146	      SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13147	
13148	      /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13149	      assert(added);
13150	   }
13151	
13152	   /* create and add auxexpr */
13153	   SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
13154	   auxexpr->underestimate = !overestimate;
13155	   auxexpr->overestimate = overestimate;
13156	   auxexpr->auxvar = auxvar;
13157	   auxexpr->coefs[0] = coefaux;
13158	   if( term->x == x )
13159	   {
13160	      assert(term->y == y);
13161	      auxexpr->coefs[1] = coefx;
13162	      auxexpr->coefs[2] = coefy;
13163	   }
13164	   else
13165	   {
13166	      assert(term->x == y);
13167	      assert(term->y == x);
13168	      auxexpr->coefs[1] = coefy;
13169	      auxexpr->coefs[2] = coefx;
13170	   }
13171	   auxexpr->cst = cst;
13172	   SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13173	
13174	   if( !added )
13175	   {
13176	      SCIPfreeBlockMemory(scip, &auxexpr);
13177	   }
13178	   else if( auxvar != NULL )
13179	   { /* capture auxiliary variable */
13180	      SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13181	   }
13182	
13183	   return SCIP_OKAY;
13184	}
13185	
13186	/* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13187	SCIP_RETCODE SCIPcomputeFacetVertexPolyhedralNonlinear(
13188	   SCIP*                 scip,               /**< SCIP data structure */
13189	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
13190	   SCIP_Bool             overestimate,       /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13191	   SCIP_DECL_VERTEXPOLYFUN((*function)),     /**< pointer to vertex polyhedral function */
13192	   void*                 fundata,            /**< data for function evaluation (can be NULL) */
13193	   SCIP_Real*            xstar,              /**< point to be separated */
13194	   SCIP_Real*            box,                /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13195	   int                   nallvars,           /**< half of the length of box */
13196	   SCIP_Real             targetvalue,        /**< target value: no need to compute facet if value in xstar would be worse than this value */
13197	   SCIP_Bool*            success,            /**< buffer to store whether a facet could be computed successfully */
13198	   SCIP_Real*            facetcoefs,         /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13199	   SCIP_Real*            facetconstant       /**< buffer to store constant part of facet defining inequality */
13200	   )
13201	{
13202	   SCIP_Real* corner;
13203	   SCIP_Real* funvals;
13204	   int* nonfixedpos;
13205	   SCIP_Real maxfaceterror;
13206	   int nvars; /* number of nonfixed variables */
13207	   unsigned int ncorners;
13208	   unsigned int i;
13209	   int j;
13210	
13211	   assert(scip != NULL);
13212	   assert(conshdlr != NULL);
13213	   assert(function != NULL);
13214	   assert(xstar != NULL);
13215	   assert(box != NULL);
13216	   assert(success != NULL);
13217	   assert(facetcoefs != NULL);
13218	   assert(facetconstant != NULL);
13219	
13220	   *success = FALSE;
13221	
13222	   /* identify fixed variables */
13223	   SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
13224	   nvars = 0;
13225	   for( j = 0; j < nallvars; ++j )
13226	   {
13227	      if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13228	         continue;
13229	      nonfixedpos[nvars] = j;
13230	      nvars++;
13231	   }
13232	
13233	   /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13234	    * if too many variables are not fixed, then we do nothing currently
13235	    */
13236	   if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13237	   {
13238	      SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13239	      SCIPfreeBufferArray(scip, &nonfixedpos);
13240	      return SCIP_OKAY;
13241	   }
13242	
13243	   /* compute f(v^i) for each corner v^i of [l,u] */
13244	   ncorners = POWEROFTWO(nvars);
13245	   SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
13246	   SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13247	   for( j = 0; j < nallvars; ++j )
13248	   {
13249	      if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13250	         corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13251	   }
13252	   for( i = 0; i < ncorners; ++i )
13253	   {
13254	      SCIPdebugMsg(scip, "corner %u: ", i);
13255	      for( j = 0; j < nvars; ++j )
13256	      {
13257	         int varpos = nonfixedpos[j];
13258	         /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13259	          * we check this by shifting i for j positions to the right and checking whether the last bit is set
13260	          */
13261	         if( (i >> j) & 0x1 )
13262	            corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13263	         else
13264	            corner[varpos] = box[2 * varpos ]; /* lb of var */
13265	         SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13266	         assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
13267	      }
13268	
13269	      funvals[i] = function(corner, nallvars, fundata);
13270	
13271	      SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13272	
13273	      if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
13274	      {
13275	         SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13276	         goto CLEANUP;
13277	      }
13278	   }
13279	
13280	   /* clear coefs array; below we only fill in coefs for nonfixed variables */
13281	   BMSclearMemoryArray(facetcoefs, nallvars);
13282	
13283	   if( nvars == 1 )
13284	   {
13285	      SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
13286	
13287	      /* check whether target has been missed */
13288	      if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13289	      {
13290	         SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13291	         *success = FALSE;
13292	      }
13293	   }
13294	   else if( nvars == 2 && SCIPlapackIsAvailable() )
13295	   {
13296	      int idx1 = nonfixedpos[0];
13297	      int idx2 = nonfixedpos[1];
13298	      SCIP_Real p1[2] = { box[2*idx1],   box[2*idx2]   }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13299	      SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2]   }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13300	      SCIP_Real p3[2] = { box[2*idx1],   box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13301	      SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13302	      SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13303	      SCIP_Real coefs[2] = { 0.0, 0.0 };
13304	
13305	      SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13306	
13307	      facetcoefs[idx1] = coefs[0];
13308	      facetcoefs[idx2] = coefs[1];
13309	   }
13310	   else
13311	   {
13312	      SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13313	   }
13314	   if( !*success )
13315	   {
13316	      SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13317	      goto CLEANUP;
13318	   }
13319	
13320	   /*
13321	    *  check and adjust facet with the algorithm of Rikun et al.
13322	    */
13323	
13324	   maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
13325	
13326	   /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13327	   if( maxfaceterror > 0.0 )
13328	   {
13329	      SCIP_CONSHDLRDATA* conshdlrdata;
13330	      SCIP_Real midval;
13331	      SCIP_Real feastol;
13332	
13333	      feastol = SCIPgetStage(scip) == SCIP_STAGE_SOLVING ? SCIPgetLPFeastol(scip) : SCIPfeastol(scip);
13334	
13335	      /* evaluate function in middle point to get some idea for a scaling */
13336	      for( j = 0; j < nvars; ++j )
13337	         corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13338	      midval = function(corner, nallvars, fundata);
13339	      if( midval == SCIP_INVALID )
13340	         midval = 1.0;
13341	
13342	      conshdlrdata = SCIPconshdlrGetData(conshdlr);
13343	      assert(conshdlrdata != NULL);
13344	
13345	      /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
13346	      if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
13347	      {
13348	         SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
13349	         *success = FALSE;
13350	         goto CLEANUP;
13351	      }
13352	
13353	      SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
13354	
13355	      if( overestimate )
13356	         *facetconstant += maxfaceterror;
13357	      else
13358	         *facetconstant -= maxfaceterror;
13359	   }
13360	
13361	   /* if we made it until here, then we have a nice facet */
13362	   assert(*success);
13363	
13364	CLEANUP:
13365	   /* free allocated memory */
13366	   SCIPfreeBufferArray(scip, &corner);
13367	   SCIPfreeBufferArray(scip, &funvals);
13368	   SCIPfreeBufferArray(scip, &nonfixedpos);
13369	
13370	   return SCIP_OKAY;
13371	}
13372	
13373	/*
13374	 * constraint specific interface methods
13375	 */
13376	
13377	/** returns the expression of the given nonlinear constraint */
13378	SCIP_EXPR* SCIPgetExprNonlinear(
13379	   SCIP_CONS*            cons                /**< constraint data */
13380	   )
13381	{
13382	   SCIP_CONSDATA* consdata;
13383	
13384	   assert(cons != NULL);
13385	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13386	
13387	   consdata = SCIPconsGetData(cons);
13388	   assert(consdata != NULL);
13389	
13390	   return consdata->expr;
13391	}
13392	
13393	/** gets the left hand side of a nonlinear constraint */
13394	SCIP_Real SCIPgetLhsNonlinear(
13395	   SCIP_CONS*            cons                /**< constraint data */
13396	   )
13397	{
13398	   SCIP_CONSDATA* consdata;
13399	
13400	   assert(cons != NULL);
13401	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13402	
13403	   consdata = SCIPconsGetData(cons);
13404	   assert(consdata != NULL);
13405	
13406	   return consdata->lhs;
13407	}
13408	
13409	/** gets the right hand side of a nonlinear constraint */
13410	SCIP_Real SCIPgetRhsNonlinear(
13411	   SCIP_CONS*            cons                /**< constraint data */
13412	   )
13413	{
13414	   SCIP_CONSDATA* consdata;
13415	
13416	   assert(cons != NULL);
13417	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13418	
13419	   consdata = SCIPconsGetData(cons);
13420	   assert(consdata != NULL);
13421	
13422	   return consdata->rhs;
13423	}
13424	
13425	/** gets the nonlinear constraint as a nonlinear row representation. */
13426	SCIP_RETCODE SCIPgetNlRowNonlinear(
13427	   SCIP*                 scip,               /**< SCIP data structure */
13428	   SCIP_CONS*            cons,               /**< constraint */
13429	   SCIP_NLROW**          nlrow               /**< pointer to store nonlinear row */
13430	   )
13431	{
13432	   SCIP_CONSDATA* consdata;
13433	
13434	   assert(cons  != NULL);
13435	   assert(nlrow != NULL);
13436	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13437	
13438	   consdata = SCIPconsGetData(cons);
13439	   assert(consdata != NULL);
13440	
13441	   if( consdata->nlrow == NULL )
13442	   {
13443	      SCIP_CALL( createNlRow(scip, cons) );
13444	   }
13445	   assert(consdata->nlrow != NULL);
13446	   *nlrow = consdata->nlrow;
13447	
13448	   return SCIP_OKAY;
13449	}
13450	
13451	/** returns the curvature of the expression of a given nonlinear constraint
13452	 *
13453	 * @note The curvature information is computed during CONSINITSOL.
13454	 */
13455	SCIP_EXPRCURV SCIPgetCurvatureNonlinear(
13456	   SCIP_CONS*            cons                /**< constraint data */
13457	   )
13458	{
13459	   SCIP_CONSDATA* consdata;
13460	
13461	   assert(cons != NULL);
13462	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13463	
13464	   consdata = SCIPconsGetData(cons);
13465	   assert(consdata != NULL);
13466	
13467	   return consdata->curv;
13468	}
13469	
13470	/** checks whether expression of constraint can be represented as quadratic form
13471	 *
13472	 * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
13473	 * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
13474	 * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
13475	 */
13476	SCIP_RETCODE SCIPcheckQuadraticNonlinear(
13477	   SCIP*                 scip,               /**< SCIP data structure */
13478	   SCIP_CONS*            cons,               /**< constraint data */
13479	   SCIP_Bool*            isquadratic         /**< buffer to store whether constraint is quadratic */
13480	   )
13481	{
13482	   SCIP_CONSDATA* consdata;
13483	
13484	   assert(scip != NULL);
13485	   assert(cons != NULL);
13486	   assert(isquadratic != NULL);
13487	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13488	
13489	   consdata = SCIPconsGetData(cons);
13490	   assert(consdata != NULL);
13491	   assert(consdata->expr != NULL);
13492	
13493	   /* check whether constraint expression is quadratic in extended formulation */
13494	   SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
13495	
13496	   /* if not quadratic in non-extended formulation, then do indicate quadratic */
13497	   if( *isquadratic )
13498	      *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
13499	
13500	   return SCIP_OKAY;
13501	}
13502	
13503	/** changes left-hand-side of a nonlinear constraint
13504	 *
13505	 * @attention This method can only be called in the problem stage.
13506	 */
13507	SCIP_RETCODE SCIPchgLhsNonlinear(
13508	   SCIP*                 scip,               /**< SCIP data structure */
13509	   SCIP_CONS*            cons,               /**< constraint data */
13510	   SCIP_Real             lhs                 /**< new left-hand-side */
13511	   )
13512	{
13513	   SCIP_CONSDATA* consdata;
13514	
13515	   assert(scip != NULL);
13516	   assert(cons != NULL);
13517	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13518	
13519	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13520	   {
13521	      SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13522	      return SCIP_INVALIDCALL;
13523	   }
13524	
13525	   /* we should have an original constraint */
13526	   assert(SCIPconsIsOriginal(cons));
13527	
13528	   consdata = SCIPconsGetData(cons);
13529	   assert(consdata != NULL);
13530	
13531	   if( consdata->lhs == lhs )
13532	      return SCIP_OKAY;
13533	
13534	   consdata->lhs = lhs;
13535	
13536	   /* not sure we care about any of these flags for original constraints */
13537	   consdata->ispropagated = FALSE;
13538	
13539	   return SCIP_OKAY;
13540	}
13541	
13542	/** changes right-hand-side of a nonlinear constraint
13543	 *
13544	 * @attention This method can only be called in the problem stage.
13545	 */
13546	SCIP_RETCODE SCIPchgRhsNonlinear(
13547	   SCIP*                 scip,               /**< SCIP data structure */
13548	   SCIP_CONS*            cons,               /**< constraint data */
13549	   SCIP_Real             rhs                 /**< new right-hand-side */
13550	   )
13551	{
13552	   SCIP_CONSDATA* consdata;
13553	
13554	   assert(scip != NULL);
13555	   assert(cons != NULL);
13556	   assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13557	
13558	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13559	   {
13560	      SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13561	      return SCIP_INVALIDCALL;
13562	   }
13563	
13564	   /* we should have an original constraint */
13565	   assert(SCIPconsIsOriginal(cons));
13566	
13567	   consdata = SCIPconsGetData(cons);
13568	   assert(consdata != NULL);
13569	
13570	   if( consdata->rhs == rhs )
13571	      return SCIP_OKAY;
13572	
13573	   consdata->rhs = rhs;
13574	
13575	   /* not sure we care about any of these flags for original constraints */
13576	   consdata->ispropagated = FALSE;
13577	
13578	   return SCIP_OKAY;
13579	}
13580	
13581	/** changes expression of a nonlinear constraint
13582	 *
13583	 * @attention This method can only be called in the problem stage.
13584	 */
13585	SCIP_RETCODE SCIPchgExprNonlinear(
13586	   SCIP*                 scip,               /**< SCIP data structure */
13587	   SCIP_CONS*            cons,               /**< constraint data */
13588	   SCIP_EXPR*            expr                /**< new expression */
13589	   )
13590	{
13591	   SCIP_CONSHDLR* conshdlr;
13592	   SCIP_CONSDATA* consdata;
13593	
13594	   assert(scip != NULL);
13595	   assert(cons != NULL);
13596	   assert(expr != NULL);
13597	
13598	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13599	   {
13600	      SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
13601	      return SCIP_INVALIDCALL;
13602	   }
13603	
13604	   /* we should have an original constraint */
13605	   assert(SCIPconsIsOriginal(cons));
13606	
13607	   conshdlr = SCIPconsGetHdlr(cons);
13608	   assert(conshdlr != NULL);
13609	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13610	
13611	   consdata = SCIPconsGetData(cons);
13612	   assert(consdata != NULL);
13613	   assert(consdata->expr != NULL);
13614	
13615	   /* we should not have collected additional data for the expr
13616	    * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
13617	    */
13618	   assert(consdata->nvarexprs == 0);
13619	   assert(consdata->varexprs == NULL);
13620	   assert(!consdata->catchedevents);
13621	
13622	   SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
13623	
13624	   /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
13625	   SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
13626	
13627	   /* not sure we care about any of these flags for original constraints */
13628	   consdata->curv = SCIP_EXPRCURV_UNKNOWN;
13629	   consdata->issimplified = FALSE;
13630	   consdata->ispropagated = FALSE;
13631	
13632	   return SCIP_OKAY;
13633	}
13634	
13635	/** adds coef * var to nonlinear constraint
13636	 *
13637	 * @attention This method can only be called in the problem stage.
13638	 */
13639	SCIP_RETCODE SCIPaddLinearVarNonlinear(
13640	   SCIP*                 scip,               /**< SCIP data structure */
13641	   SCIP_CONS*            cons,               /**< constraint data */
13642	   SCIP_VAR*             var,                /**< variable */
13643	   SCIP_Real             coef                /**< coefficient */
13644	   )
13645	{
13646	   SCIP_CONSHDLR* conshdlr;
13647	   SCIP_CONSDATA* consdata;
13648	   SCIP_EXPR* varexpr;
13649	
13650	   assert(scip != NULL);
13651	   assert(cons != NULL);
13652	
13653	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13654	   {
13655	      SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
13656	      return SCIP_INVALIDCALL;
13657	   }
13658	
13659	   /* we should have an original constraint */
13660	   assert(SCIPconsIsOriginal(cons));
13661	
13662	   if( coef == 0.0 )
13663	      return SCIP_OKAY;
13664	
13665	   conshdlr = SCIPconsGetHdlr(cons);
13666	   assert(conshdlr != NULL);
13667	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13668	
13669	   consdata = SCIPconsGetData(cons);
13670	   assert(consdata != NULL);
13671	   assert(consdata->expr != NULL);
13672	
13673	   /* we should not have collected additional data for it
13674	    * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
13675	    */
13676	   assert(consdata->nvarexprs == 0);
13677	   assert(consdata->varexprs == NULL);
13678	   assert(!consdata->catchedevents);
13679	
13680	   SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
13681	
13682	   /* append to sum, if consdata->expr is sum and not used anywhere else */
13683	   if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
13684	   {
13685	      SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
13686	   }
13687	   else
13688	   {
13689	      /* create new expression = 1 * consdata->expr + coef * var */
13690	      SCIP_EXPR* children[2] = { consdata->expr, varexpr };
13691	      SCIP_Real coefs[2] = { 1.0, coef };
13692	
13693	      SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
13694	
13695	      /* release old root expr */
13696	      SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
13697	   }
13698	
13699	   SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
13700	
13701	   /* not sure we care about any of these flags for original constraints */
13702	   consdata->issimplified = FALSE;
13703	   consdata->ispropagated = FALSE;
13704	
13705	   return SCIP_OKAY;
13706	}
13707	
13708	/** adds coef * expr to nonlinear constraint
13709	 *
13710	 * @attention This method can only be called in the problem stage.
13711	 */
13712	SCIP_RETCODE SCIPaddExprNonlinear(
13713	   SCIP*                 scip,               /**< SCIP data structure */
13714	   SCIP_CONS*            cons,               /**< nonlinear constraint */
13715	   SCIP_EXPR*            expr,               /**< expression */
13716	   SCIP_Real             coef                /**< coefficient */
13717	   )
13718	{
13719	   SCIP_CONSHDLR* conshdlr;
13720	   SCIP_CONSDATA* consdata;
13721	   SCIP_EXPR* exprowned;
13722	
13723	   assert(scip != NULL);
13724	   assert(cons != NULL);
13725	
13726	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13727	   {
13728	      SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
13729	      return SCIP_INVALIDCALL;
13730	   }
13731	
13732	   /* we should have an original constraint */
13733	   assert(SCIPconsIsOriginal(cons));
13734	
13735	   if( coef == 0.0 )
13736	      return SCIP_OKAY;
13737	
13738	   conshdlr = SCIPconsGetHdlr(cons);
13739	   assert(conshdlr != NULL);
13740	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13741	
13742	   consdata = SCIPconsGetData(cons);
13743	   assert(consdata != NULL);
13744	   assert(consdata->expr != NULL);
13745	
13746	   /* we should not have collected additional data for it
13747	    * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
13748	    */
13749	   assert(consdata->nvarexprs == 0);
13750	   assert(consdata->varexprs == NULL);
13751	   assert(!consdata->catchedevents);
13752	
13753	   /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
13754	   SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
13755	
13756	   /* append to sum, if consdata->expr is sum and not used anywhere else */
13757	   if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
13758	   {
13759	      SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
13760	   }
13761	   else
13762	   {
13763	      /* create new expression = 1 * consdata->expr + coef * var */
13764	      SCIP_EXPR* children[2] = { consdata->expr, exprowned };
13765	      SCIP_Real coefs[2] = { 1.0, coef };
13766	
13767	      SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
13768	
13769	      /* release old root expr */
13770	      SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
13771	   }
13772	
13773	   SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
13774	
13775	   /* not sure we care about any of these flags for original constraints */
13776	   consdata->issimplified = FALSE;
13777	   consdata->ispropagated = FALSE;
13778	
13779	   return SCIP_OKAY;
13780	}
13781	
13782	/** gets absolute violation of nonlinear constraint
13783	 *
13784	 * This function evaluates the constraints in the given solution.
13785	 *
13786	 * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
13787	 */
13788	SCIP_RETCODE SCIPgetAbsViolationNonlinear(
13789	   SCIP*                 scip,               /**< SCIP data structure */
13790	   SCIP_CONS*            cons,               /**< constraint */
13791	   SCIP_SOL*             sol,                /**< solution to check */
13792	   SCIP_Real*            viol                /**< buffer to store computed violation */
13793	   )
13794	{
13795	   assert(cons != NULL);
13796	   assert(viol != NULL);
13797	
13798	   SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
13799	   *viol = getConsAbsViolation(cons);
13800	
13801	   return SCIP_OKAY;
13802	}
13803	
13804	/** gets scaled violation of nonlinear constraint
13805	 *
13806	 * This function evaluates the constraints in the given solution.
13807	 *
13808	 * The scaling that is applied to the absolute violation of the constraint
13809	 * depends on the setting of parameter constraints/nonlinear/violscale.
13810	 */
13811	SCIP_RETCODE SCIPgetRelViolationNonlinear(
13812	   SCIP*                 scip,               /**< SCIP data structure */
13813	   SCIP_CONS*            cons,               /**< constraint */
13814	   SCIP_SOL*             sol,                /**< solution to check */
13815	   SCIP_Real*            viol                /**< buffer to store computed violation */
13816	   )
13817	{
13818	   assert(cons != NULL);
13819	   assert(viol != NULL);
13820	
13821	   SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
13822	   SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
13823	
13824	   return SCIP_OKAY;
13825	}
13826	
13827	/** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
13828	void SCIPgetLinvarMayDecreaseNonlinear(
13829	   SCIP*                 scip,               /**< SCIP data structure */
13830	   SCIP_CONS*            cons,               /**< nonlinear constraint */
13831	   SCIP_VAR**            var,                /**< pointer to store the variable */
13832	   SCIP_Real*            coef                /**< pointer to store the coefficient */
13833	   )
13834	{
13835	   SCIP_CONSDATA* consdata;
13836	
13837	   assert(cons != NULL);
13838	   assert(var != NULL);
13839	   assert(coef != NULL);
13840	
13841	   /* check for a linear variable that can be increased or decreased without harming feasibility */
13842	   findUnlockedLinearVar(scip, cons);
13843	
13844	   consdata = SCIPconsGetData(cons);
13845	   assert(consdata != NULL);
13846	
13847	   *var = consdata->linvardecr;
13848	   *coef = consdata->linvardecrcoef;
13849	}
13850	
13851	/** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
13852	void SCIPgetLinvarMayIncreaseNonlinear(
13853	   SCIP*                 scip,               /**< SCIP data structure */
13854	   SCIP_CONS*            cons,               /**< nonlinear constraint */
13855	   SCIP_VAR**            var,                /**< pointer to store the variable */
13856	   SCIP_Real*            coef                /**< pointer to store the coefficient */
13857	   )
13858	{
13859	   SCIP_CONSDATA* consdata;
13860	
13861	   assert(cons != NULL);
13862	   assert(var != NULL);
13863	   assert(coef != NULL);
13864	
13865	   /* check for a linear variable that can be increased or decreased without harming feasibility */
13866	   findUnlockedLinearVar(scip, cons);
13867	
13868	   consdata = SCIPconsGetData(cons);
13869	   assert(consdata != NULL);
13870	
13871	   *var = consdata->linvarincr;
13872	   *coef = consdata->linvarincrcoef;
13873	}
13874	
13875	
13876	/*
13877	 * Methods for Expressions in Nonlinear Constraints
13878	 */
13879	
13880	/** returns the number of positive rounding locks of an expression */
13881	int SCIPgetExprNLocksPosNonlinear(
13882	   SCIP_EXPR*            expr                /**< expression */
13883	   )
13884	{
13885	   assert(expr != NULL);
13886	   assert(SCIPexprGetOwnerData(expr) != NULL);
13887	
13888	   return SCIPexprGetOwnerData(expr)->nlockspos;
13889	}
13890	
13891	/** returns the number of negative rounding locks of an expression */
13892	int SCIPgetExprNLocksNegNonlinear(
13893	   SCIP_EXPR*            expr                /**< expression */
13894	   )
13895	{
13896	   assert(expr != NULL);
13897	   assert(SCIPexprGetOwnerData(expr) != NULL);
13898	
13899	   return SCIPexprGetOwnerData(expr)->nlocksneg;
13900	}
13901	
13902	/** returns the variable used for linearizing a given expression (return value might be NULL)
13903	 *
13904	 * @note for variable expression it returns the corresponding variable
13905	 */
13906	SCIP_VAR* SCIPgetExprAuxVarNonlinear(
13907	   SCIP_EXPR*            expr                /**< expression */
13908	   )
13909	{
13910	   SCIP_EXPR_OWNERDATA* ownerdata;
13911	
13912	   assert(expr != NULL);
13913	
13914	   ownerdata = SCIPexprGetOwnerData(expr);
13915	   assert(ownerdata != NULL);
13916	
13917	   return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
13918	}
13919	
13920	/** returns the number of enforcements for an expression */
13921	int SCIPgetExprNEnfosNonlinear(
13922	   SCIP_EXPR*            expr                /**< expression */
13923	   )
13924	{
13925	   assert(expr != NULL);
13926	   assert(SCIPexprGetOwnerData(expr) != NULL);
13927	
13928	   return SCIPexprGetOwnerData(expr)->nenfos;
13929	}
13930	
13931	/** returns the data for one of the enforcements of an expression */
13932	void SCIPgetExprEnfoDataNonlinear(
13933	   SCIP_EXPR*            expr,               /**< expression */
13934	   int                   idx,                /**< position of enforcement in enfos array */
13935	   SCIP_NLHDLR**         nlhdlr,             /**< buffer to store nlhldr */
13936	   SCIP_NLHDLREXPRDATA** nlhdlrexprdata,     /**< buffer to store nlhdlr data for expression, or NULL */
13937	   SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
13938	   SCIP_Bool*            sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
13939	   SCIP_Bool*            sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
13940	   SCIP_Real*            auxvalue            /**< buffer to store current auxvalue, or NULL */
13941	   )
13942	{
13943	   SCIP_EXPR_OWNERDATA* ownerdata;
13944	
13945	   assert(expr != NULL);
13946	
13947	   ownerdata = SCIPexprGetOwnerData(expr);
13948	   assert(ownerdata != NULL);
13949	   assert(idx >= 0);
13950	   assert(idx < ownerdata->nenfos);
13951	   assert(ownerdata->enfos[idx] != NULL);
13952	   assert(nlhdlr != NULL);
13953	
13954	   *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
13955	
13956	   if( nlhdlrexprdata != NULL )
13957	      *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
13958	
13959	   if( nlhdlrparticipation != NULL )
13960	      *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
13961	
13962	   if( sepabelowusesactivity != NULL )
13963	      *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
13964	
13965	   if( sepaaboveusesactivity != NULL )
13966	      *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
13967	
13968	   if( auxvalue != NULL )
13969	      *auxvalue = ownerdata->enfos[idx]->auxvalue;
13970	}
13971	
13972	/** sets the auxiliary value of expression for one of the enforcements of an expression */
13973	void SCIPsetExprEnfoAuxValueNonlinear(
13974	   SCIP_EXPR*            expr,               /**< expression */
13975	   int                   idx,                /**< position of enforcement in enfos array */
13976	   SCIP_Real             auxvalue            /**< the new value of auxval */
13977	   )
13978	{
13979	   SCIP_EXPR_OWNERDATA* ownerdata;
13980	
13981	   assert(expr != NULL);
13982	
13983	   ownerdata = SCIPexprGetOwnerData(expr);
13984	   assert(ownerdata != NULL);
13985	
13986	   assert(idx >= 0);
13987	   assert(idx < ownerdata->nenfos);
13988	   assert(ownerdata->enfos[idx] != NULL);
13989	
13990	   ownerdata->enfos[idx]->auxvalue = auxvalue;
13991	}
13992	
13993	/** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
13994	 *
13995	 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
13996	 */
13997	unsigned int SCIPgetExprNPropUsesActivityNonlinear(
13998	   SCIP_EXPR*            expr                /**< expression */
13999	   )
14000	{
14001	   assert(expr != NULL);
14002	   assert(SCIPexprGetOwnerData(expr) != NULL);
14003	
14004	   return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14005	}
14006	
14007	/** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14008	 *
14009	 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14010	 */
14011	unsigned int SCIPgetExprNSepaUsesActivityNonlinear(
14012	   SCIP_EXPR*            expr                /**< expression */
14013	   )
14014	{
14015	   assert(expr != NULL);
14016	   assert(SCIPexprGetOwnerData(expr) != NULL);
14017	
14018	   return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14019	}
14020	
14021	/** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14022	 *
14023	 * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14024	 */
14025	unsigned int SCIPgetExprNAuxvarUsesNonlinear(
14026	   SCIP_EXPR*            expr                /**< expression */
14027	   )
14028	{
14029	   assert(expr != NULL);
14030	   assert(SCIPexprGetOwnerData(expr) != NULL);
14031	
14032	   return SCIPexprGetOwnerData(expr)->nauxvaruses;
14033	}
14034	
14035	/** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14036	 *
14037	 * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14038	 * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14039	 * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14040	 * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14041	 *   and also increments this count for all variables in the expression.
14042	 *
14043	 * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14044	 * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14045	 * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14046	 * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14047	 */
14048	SCIP_RETCODE SCIPregisterExprUsageNonlinear(
14049	   SCIP*                 scip,               /**< SCIP data structure */
14050	   SCIP_EXPR*            expr,               /**< expression */
14051	   SCIP_Bool             useauxvar,          /**< whether an auxiliary variable will be used for estimate or cut generation */
14052	   SCIP_Bool             useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14053	   SCIP_Bool             useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14054	   SCIP_Bool             useactivityforsepaabove  /**< whether activity of expr will be used by overestimation */
14055	   )
14056	{
14057	   SCIP_EXPR_OWNERDATA* ownerdata;
14058	
14059	   assert(expr != NULL);
14060	
14061	   ownerdata = SCIPexprGetOwnerData(expr);
14062	   assert(ownerdata != NULL);
14063	
14064	   /* do not store auxvar request for variable expressions */
14065	   if( useauxvar && SCIPisExprVar(scip, expr) )
14066	      useauxvar = FALSE;
14067	
14068	   if( ownerdata->nenfos >= 0 &&
14069	      ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14070	        (ownerdata->nauxvaruses == 0 && useauxvar)
14071	      ) )
14072	   {
14073	      /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14074	       * we require additional enforcement methods, that is,
14075	       * - activity of expr was not used before but will be used now, or
14076	       * - auxiliary variable of expr was not required before but will be used now
14077	       */
14078	      SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14079	   }
14080	
14081	   if( useauxvar )
14082	      ++ownerdata->nauxvaruses;
14083	
14084	   if( useactivityforprop )
14085	      ++ownerdata->nactivityusesprop;
14086	
14087	   if( useactivityforsepabelow || useactivityforsepaabove )
14088	      ++ownerdata->nactivityusessepa;
14089	
14090	   /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14091	    * information is used in detectNlhdlr()
14092	    */
14093	   if( useactivityforsepabelow )
14094	      SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14095	   if( useactivityforsepaabove )
14096	      SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14097	
14098	   if( useactivityforprop )
14099	   {
14100	      /* if activity will be used for propagation, then make sure there is a valid activity
14101	       * this way, we can do a reversepropcall after detectNlhdlr
14102	       */
14103	      SCIP_CALL( SCIPevalExprActivity(scip, expr) );
14104	   }
14105	
14106	   /* increase the nactivityusedsepa counter for all variables used in the given expression */
14107	   if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
14108	   {
14109	      SCIP_EXPRITER* it;
14110	
14111	      /* create and initialize iterator */
14112	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
14113	      SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, FALSE) );
14114	
14115	      for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14116	         if( SCIPisExprVar(scip, expr) )
14117	            ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14118	
14119	      /* free iterator */
14120	      SCIPfreeExpriter(&it);
14121	   }
14122	
14123	   return SCIP_OKAY;
14124	}
14125	
14126	/** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14127	 *
14128	 * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14129	 * Assume that f(x) is associated with auxiliary variable z.
14130	 *
14131	 * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14132	 * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14133	 * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14134	 *
14135	 * If necessary, f is evaluated in the given solution. If that fails (domain error),
14136	 * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14137	 */
14138	SCIP_RETCODE SCIPgetExprAbsOrigViolationNonlinear(
14139	   SCIP*                 scip,               /**< SCIP data structure */
14140	   SCIP_EXPR*            expr,               /**< expression */
14141	   SCIP_SOL*             sol,                /**< solution */
14142	   SCIP_Longint          soltag,             /**< tag of solution */
14143	   SCIP_Real*            viol,               /**< buffer to store computed violation */
14144	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(x) is violated, or NULL */
14145	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(x) is violated, or NULL */
14146	   )
14147	{
14148	   assert(scip != NULL);
14149	   assert(expr != NULL);
14150	   assert(viol != NULL);
14151	
14152	   /* make sure expression has been evaluated */
14153	   SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14154	
14155	   /* get violation from internal method */
14156	   *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
14157	
14158	   return SCIP_OKAY;
14159	}
14160	
14161	/** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14162	 *
14163	 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14164	 * Assume that f(w) is associated with auxiliary variable z.
14165	 *
14166	 * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14167	 * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14168	 * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14169	 *
14170	 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14171	 * both `violover` and `violunder` are set to TRUE.
14172	 */
14173	SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(
14174	   SCIP*                 scip,               /**< SCIP data structure */
14175	   SCIP_EXPR*            expr,               /**< expression */
14176	   SCIP_Real             auxvalue,           /**< the value of f(w) */
14177	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
14178	   SCIP_Real*            viol,               /**< buffer to store computed violation */
14179	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(w) is violated, or NULL */
14180	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(w) is violated, or NULL */
14181	   )
14182	{
14183	   assert(scip != NULL);
14184	   assert(expr != NULL);
14185	   assert(viol != NULL);
14186	
14187	   /* get violation from internal method */
14188	   *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14189	
14190	   return SCIP_OKAY;
14191	}
14192	
14193	
14194	/** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14195	 *
14196	 * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14197	 * Assume that f(w) is associated with auxiliary variable z.
14198	 *
14199	 * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14200	 * the absolute violation divided by max(1,|f(w)|).
14201	 *
14202	 * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14203	 * both `violover` and `violunder` are set to TRUE.
14204	 */
14205	SCIP_RETCODE SCIPgetExprRelAuxViolationNonlinear(
14206	   SCIP*                 scip,               /**< SCIP data structure */
14207	   SCIP_EXPR*            expr,               /**< expression */
14208	   SCIP_Real             auxvalue,           /**< the value of f(w) */
14209	   SCIP_SOL*             sol,                /**< solution that has been evaluated */
14210	   SCIP_Real*            viol,               /**< buffer to store computed violation */
14211	   SCIP_Bool*            violunder,          /**< buffer to store whether z >= f(w) is violated, or NULL */
14212	   SCIP_Bool*            violover            /**< buffer to store whether z <= f(w) is violated, or NULL */
14213	   )
14214	{
14215	   assert(scip != NULL);
14216	   assert(expr != NULL);
14217	   assert(viol != NULL);
14218	
14219	   /* get violation from internal method */
14220	   *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14221	
14222	   if( !SCIPisInfinity(scip, *viol) )
14223	   {
14224	      assert(auxvalue != SCIP_INVALID);
14225	      /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14226	      *viol /= MAX(1.0, REALABS(auxvalue));
14227	   }
14228	
14229	   return SCIP_OKAY;
14230	}
14231	
14232	/** returns bounds on the expression
14233	 *
14234	 * This gives an intersection of bounds from
14235	 * - activity calculation (SCIPexprGetActivity()), if valid,
14236	 * - auxiliary variable, if present,
14237	 * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14238	 *
14239	 * @note The returned interval can be empty!
14240	 */
14241	SCIP_INTERVAL SCIPgetExprBoundsNonlinear(
14242	   SCIP*                 scip,               /**< SCIP data structure */
14243	   SCIP_EXPR*            expr                /**< expression */
14244	   )
14245	{
14246	   SCIP_EXPR_OWNERDATA* ownerdata;
14247	   SCIP_CONSHDLRDATA* conshdlrdata;
14248	   SCIP_INTERVAL bounds;
14249	
14250	   assert(scip != NULL);
14251	   assert(expr != NULL);
14252	
14253	   ownerdata = SCIPexprGetOwnerData(expr);
14254	   assert(ownerdata != NULL);
14255	
14256	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14257	   assert(conshdlrdata != NULL);
14258	
14259	   /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14260	
14261	   /* start with propbounds if they belong to current propagation */
14262	   if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14263	   {
14264	      bounds = ownerdata->propbounds;
14265	      /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14266	   }
14267	   else
14268	      SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &bounds);
14269	
14270	   if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14271	   {
14272	      /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14273	      /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14274	      SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), bounds);
14275	   }
14276	
14277	   if( ownerdata->auxvar != NULL )
14278	   {
14279	      /* apply auxiliary variable bounds to bounds */
14280	      SCIP_INTERVAL auxvarbounds;
14281	
14282	      auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14283	      /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14284	      SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
14285	   }
14286	
14287	   /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14288	
14289	   return bounds;
14290	}
14291	
14292	/** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14293	 * corresponding (auxiliary) variable (if any)
14294	 *
14295	 * @attention this function should only be called during domain propagation in cons_nonlinear
14296	 */
14297	SCIP_RETCODE SCIPtightenExprIntervalNonlinear(
14298	   SCIP*                 scip,               /**< SCIP data structure */
14299	   SCIP_EXPR*            expr,               /**< expression to be tightened */
14300	   SCIP_INTERVAL         newbounds,          /**< new bounds for the expression */
14301	   SCIP_Bool*            cutoff,             /**< buffer to store whether a cutoff was detected */
14302	   int*                  ntightenings        /**< buffer to add the total number of tightenings, or NULL */
14303	   )
14304	{
14305	   SCIP_EXPR_OWNERDATA* ownerdata;
14306	   SCIP_CONSHDLRDATA* conshdlrdata;
14307	
14308	   assert(scip != NULL);
14309	   assert(expr != NULL);
14310	   assert(cutoff != NULL);
14311	
14312	   ownerdata = SCIPexprGetOwnerData(expr);
14313	   assert(ownerdata != NULL);
14314	   assert(ownerdata->conshdlr != NULL);
14315	
14316	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14317	   assert(conshdlrdata != NULL);
14318	
14319	   /* the code below assumes that current activity is valid
14320	    * if it turns out that we cannot ensure that, then we should change code
14321	    */
14322	   assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
14323	   assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
14324	
14325	   *cutoff = FALSE;
14326	
14327	#ifdef DEBUG_PROP
14328	   SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
14329	   SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
14330	   SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
14331	#endif
14332	
14333	   if( SCIPexprIsIntegral(expr) )
14334	   {
14335	      /* apply integrality to new bounds
14336	       * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
14337	       */
14338	      if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
14339	         newbounds.inf = SCIPceil(scip, newbounds.inf);
14340	      if( newbounds.sup <  SCIP_INTERVAL_INFINITY )
14341	         newbounds.sup = SCIPfloor(scip, newbounds.sup);
14342	#ifdef DEBUG_PROP
14343	      SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
14344	#endif
14345	   }
14346	
14347	   if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newbounds) )
14348	   {
14349	      SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
14350	
14351	      *cutoff = TRUE;
14352	      return SCIP_OKAY;
14353	   }
14354	
14355	   /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
14356	   if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
14357	   {
14358	      SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
14359	
14360	      *cutoff = TRUE;
14361	      return SCIP_OKAY;
14362	   }
14363	
14364	   /* tighten newbounds w.r.t. existing expr->propbounds or activity */
14365	   if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14366	   {
14367	      /* if already having propbounds in expr, then tighten newbounds by propbounds */
14368	      SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
14369	   }
14370	   else
14371	   {
14372	      /* first time we have propbounds for expr in this propagation rounds:
14373	       * intersect with activity (though don't let it become empty if very close intervals)
14374	       */
14375	      SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
14376	   }
14377	#ifdef DEBUG_PROP
14378	   SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
14379	#endif
14380	
14381	   /* check if the new bounds lead to an empty interval */
14382	   if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newbounds) )
14383	   {
14384	      SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
14385	
14386	      *cutoff = TRUE;
14387	      return SCIP_OKAY;
14388	   }
14389	
14390	   /* if expr is not constant or variable, then store newbounds in expr->propbounds
14391	    * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
14392	    * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
14393	    */
14394	   if( SCIPexprGetNChildren(expr) > 0 )
14395	   {
14396	      ownerdata->propbounds = newbounds;
14397	      ownerdata->propboundstag = conshdlrdata->curpropboundstag;
14398	   }
14399	
14400	   /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
14401	    * propagation or update of auxvar bounds
14402	    * TODO? if we first had a considerable tightening and then only get small tightenings under the same
14403	    *   curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
14404	    *   not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
14405	    *   propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
14406	    *   one or should we not even update propbounds to newbounds if the update is small?
14407	    */
14408	   if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
14409	   {
14410	#ifdef DEBUG_PROP
14411	      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);
14412	#endif
14413	      return SCIP_OKAY;
14414	   }
14415	
14416	   if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
14417	   {
14418	      /* add expression to propagation queue if not there yet and not var or constant and
14419	       * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
14420	       */
14421	#ifdef DEBUG_PROP
14422	         SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
14423	#endif
14424	         SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
14425	         ownerdata->inpropqueue = TRUE;
14426	   }
14427	
14428	   /* update bounds on variable or auxiliary variable */
14429	   SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
14430	
14431	   return SCIP_OKAY;
14432	}
14433	
14434	/** mark constraints that include this expression to be propagated again
14435	 *
14436	 * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
14437	 * a change of variable bounds, e.g., because new information on the expression is available
14438	 * that could potentially lead to tighter expression activity values.
14439	 *
14440	 * Note, that this call marks also constraints for propagation which only share some variable
14441	 * with this expression.
14442	 */
14443	SCIP_RETCODE SCIPmarkExprPropagateNonlinear(
14444	   SCIP*                 scip,               /**< SCIP data structure */
14445	   SCIP_EXPR*            expr                /**< expression to propagate again */
14446	   )
14447	{
14448	   SCIP_EXPRITER* it;
14449	   SCIP_CONSDATA* consdata;
14450	   SCIP_EXPR_OWNERDATA* ownerdata;
14451	   int c;
14452	
14453	   assert(scip != NULL);
14454	   assert(expr != NULL);
14455	
14456	   ownerdata = SCIPexprGetOwnerData(expr);
14457	   assert(ownerdata != NULL);
14458	
14459	   SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
14460	
14461	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
14462	   SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, FALSE) );
14463	
14464	   for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14465	   {
14466	      if( !SCIPisExprVar(scip, expr) )
14467	         continue;
14468	
14469	      ownerdata = SCIPexprGetOwnerData(expr);
14470	      assert(ownerdata != NULL);
14471	
14472	      for( c = 0; c < ownerdata->nconss; ++c )
14473	      {
14474	         consdata = SCIPconsGetData(ownerdata->conss[c]);
14475	         assert(consdata != NULL);
14476	         consdata->ispropagated = FALSE;
14477	      }
14478	   }
14479	
14480	   SCIPfreeExpriter(&it);
14481	
14482	   return SCIP_OKAY;
14483	}
14484	
14485	/** adds violation-branching score to an expression
14486	 *
14487	 * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
14488	 * The expression must either be a variable expression or have an aux-variable.
14489	 * In the latter case, branching on auxiliary variables must have been enabled.
14490	 * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
14491	 * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
14492	 * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
14493	 *
14494	 * @see SCIPaddExprsViolScoreNonlinear()
14495	 */
14496	void SCIPaddExprViolScoreNonlinear(
14497	   SCIP*                 scip,               /**< SCIP data structure */
14498	   SCIP_EXPR*            expr,               /**< expression where to add branching score */
14499	   SCIP_Real             violscore           /**< violation score to add to expression */
14500	   )
14501	{
14502	   SCIP_EXPR_OWNERDATA* ownerdata;
14503	   SCIP_CONSHDLRDATA* conshdlrdata;
14504	
14505	   assert(scip != NULL);
14506	   assert(expr != NULL);
14507	   assert(violscore >= 0.0);
14508	
14509	   ownerdata = SCIPexprGetOwnerData(expr);
14510	   assert(ownerdata != NULL);
14511	
14512	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14513	   assert(conshdlrdata != NULL);
14514	
14515	   /* if not allowing to branch on auxvars, then expr must be a var-expr */
14516	   assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
14517	   /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
14518	   assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
14519	
14520	   /* reset branching score if we are in a different enfo round */
14521	   if( ownerdata->violscoretag != conshdlrdata->enforound )
14522	   {
14523	      ownerdata->violscoresum = violscore;
14524	      ownerdata->violscoremax = violscore;
14525	      ownerdata->nviolscores = 1;
14526	      ownerdata->violscoretag = conshdlrdata->enforound;
14527	      return;
14528	   }
14529	
14530	   ownerdata->violscoresum += violscore;
14531	   if( violscore > ownerdata->violscoremax )
14532	      ownerdata->violscoremax = violscore;
14533	   ++ownerdata->nviolscores;
14534	}
14535	
14536	/** adds violation-branching score to a set of expressions, distributing the score among all the expressions
14537	 *
14538	 * Each expression must either be a variable expression or have an aux-variable.
14539	 * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
14540	 * variables present in `exprs`.
14541	 */
14542	SCIP_RETCODE SCIPaddExprsViolScoreNonlinear(
14543	   SCIP*                 scip,               /**< SCIP data structure */
14544	   SCIP_EXPR**           exprs,              /**< expressions where to add branching score */
14545	   int                   nexprs,             /**< number of expressions */
14546	   SCIP_Real             violscore,          /**< violation score to add to expression */
14547	   SCIP_SOL*             sol,                /**< current solution */
14548	   SCIP_Bool*            success             /**< buffer to store whether at least one violscore was added */
14549	   )
14550	{
14551	   SCIP_EXPRITER* it;
14552	   SCIP_EXPR** varexprs;
14553	   SCIP_EXPR* e;
14554	   int nvars;
14555	   int varssize;
14556	   int i;
14557	
14558	   assert(exprs != NULL || nexprs == 0);
14559	   assert(success != NULL);
14560	
14561	   if( nexprs == 0 )
14562	   {
14563	      *success = FALSE;
14564	      return SCIP_OKAY;
14565	   }
14566	
14567	   /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
14568	   if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
14569	   {
14570	      addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
14571	      return SCIP_OKAY;
14572	   }
14573	
14574	   /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
14575	   nvars = 0;
14576	   varssize = 5;
14577	   SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
14578	
14579	   SCIP_CALL( SCIPcreateExpriter(scip, &it) );
14580	   SCIP_CALL( SCIPexpriterInit(it, NULL, SCIP_EXPRITER_DFS, FALSE) );
14581	
14582	   for( i = 0; i < nexprs; ++i )
14583	   {
14584	      for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
14585	      {
14586	         assert(e != NULL);
14587	
14588	         if( SCIPisExprVar(scip, e) )
14589	         {
14590	            /* add variable expression to vars array */
14591	            if( varssize == nvars )
14592	            {
14593	               varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
14594	               SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
14595	            }
14596	            assert(varssize > nvars);
14597	
14598	            varexprs[nvars++] = e;
14599	         }
14600	      }
14601	   }
14602	
14603	   SCIPfreeExpriter(&it);
14604	
14605	   addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
14606	
14607	   SCIPfreeBufferArray(scip, &varexprs);
14608	
14609	   return SCIP_OKAY;
14610	}
14611	
14612	/** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
14613	SCIP_Real SCIPgetExprViolScoreNonlinear(
14614	   SCIP_EXPR*            expr                /**< expression */
14615	   )
14616	{
14617	   SCIP_EXPR_OWNERDATA* ownerdata;
14618	   SCIP_CONSHDLRDATA* conshdlrdata;
14619	
14620	   assert(expr != NULL);
14621	
14622	   ownerdata = SCIPexprGetOwnerData(expr);
14623	   assert(ownerdata != NULL);
14624	
14625	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14626	   assert(conshdlrdata != NULL);
14627	
14628	   if( conshdlrdata->enforound != ownerdata->violscoretag )
14629	      return 0.0;
14630	
14631	   if( ownerdata->nviolscores == 0 )
14632	      return 0.0;
14633	
14634	   switch( conshdlrdata->branchscoreagg )
14635	   {
14636	      case 'a' :
14637	         /* average */
14638	         return ownerdata->violscoresum / ownerdata->nviolscores;
14639	
14640	      case 'm' :
14641	         /* maximum */
14642	         return ownerdata->violscoremax;
14643	
14644	      case 's' :
14645	         /* sum */
14646	         return ownerdata->violscoresum;
14647	
14648	      default:
14649	         SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
14650	         SCIPABORT();
14651	         return SCIP_INVALID;
14652	   }
14653	}
14654	
14655	/** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
14656	 *
14657	 * @see SCIPexprGetDerivative()
14658	 */
14659	SCIP_Real SCIPgetExprPartialDiffNonlinear(
14660	   SCIP*                 scip,               /**< SCIP data structure */
14661	   SCIP_EXPR*            expr,               /**< root expression of constraint used in the last SCIPevalExprGradient() call */
14662	   SCIP_VAR*             var                 /**< variable (needs to be in the expression) */
14663	   )
14664	{
14665	   SCIP_EXPR_OWNERDATA* ownerdata;
14666	   SCIP_CONSHDLRDATA* conshdlrdata;
14667	   SCIP_EXPR* varexpr;
14668	
14669	   assert(scip != NULL);
14670	   assert(expr != NULL);
14671	   assert(var != NULL);
14672	
14673	   /* return 0.0 for value expression */
14674	   if( SCIPisExprValue(scip, expr) )
14675	   {
14676	      assert(SCIPexprGetDerivative(expr) == 0.0);
14677	      return 0.0;
14678	   }
14679	
14680	   /* check if an error occurred during the last SCIPevalExprGradient() call */
14681	   if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
14682	      return SCIP_INVALID;
14683	
14684	   ownerdata = SCIPexprGetOwnerData(expr);
14685	   assert(ownerdata != NULL);
14686	
14687	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14688	   assert(conshdlrdata != NULL);
14689	
14690	   /* use variable to expressions mapping which is stored in the constraint handler data */
14691	   assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
14692	
14693	   varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
14694	   assert(varexpr != NULL);
14695	   assert(SCIPisExprVar(scip, varexpr));
14696	
14697	   /* use difftag to decide whether the variable belongs to the expression */
14698	   return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
14699	}
14700	
14701	/** 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)
14702	 *
14703	 * @see SCIPexprGetBardot()
14704	 */
14705	SCIP_Real SCIPgetExprPartialDiffGradientDirNonlinear(
14706	   SCIP*                 scip,               /**< SCIP data structure */
14707	   SCIP_EXPR*            expr,               /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
14708	   SCIP_VAR*             var                 /**< variable (needs to be in the expression) */
14709	   )
14710	{
14711	   SCIP_EXPR_OWNERDATA* ownerdata;
14712	   SCIP_CONSHDLRDATA* conshdlrdata;
14713	   SCIP_EXPR* varexpr;
14714	
14715	   assert(scip != NULL);
14716	   assert(expr != NULL);
14717	   assert(var != NULL);
14718	
14719	   /* return 0.0 for value expression */
14720	   if( SCIPisExprValue(scip, expr) )
14721	      return 0.0;
14722	
14723	   /* check if an error occurred during the last SCIPevalExprHessianDir() call */
14724	   if( SCIPexprGetBardot(expr) == SCIP_INVALID )
14725	      return SCIP_INVALID;
14726	
14727	   ownerdata = SCIPexprGetOwnerData(expr);
14728	   assert(ownerdata != NULL);
14729	
14730	   conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14731	   assert(conshdlrdata != NULL);
14732	
14733	   /* use variable to expressions mapping which is stored in the constraint handler data;
14734	    * if this fails it means that we are asking for the var's component of H*u for a var
14735	    * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
14736	    */
14737	   assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
14738	
14739	   varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
14740	   assert(varexpr != NULL);
14741	   assert(SCIPisExprVar(scip, varexpr));
14742	
14743	   /* use difftag to decide whether the variable belongs to the expression */
14744	   return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
14745	}
14746	
14747	/** evaluates quadratic term in a solution w.r.t. auxiliary variables
14748	 *
14749	 * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
14750	 */
14751	SCIP_Real SCIPevalExprQuadraticAuxNonlinear(
14752	   SCIP*                 scip,               /**< SCIP data structure */
14753	   SCIP_EXPR*            expr,               /**< quadratic expression */
14754	   SCIP_SOL*             sol                 /**< solution to evaluate, or NULL for LP solution */
14755	   )
14756	{
14757	   SCIP_Real auxvalue;
14758	   int nlinexprs;
14759	   SCIP_Real* lincoefs;
14760	   SCIP_EXPR** linexprs;
14761	   int nquadexprs;
14762	   int nbilinexprs;
14763	   int i;
14764	
14765	   assert(scip != NULL);
14766	   assert(expr != NULL);
14767	
14768	   SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
14769	
14770	   /* linear terms */
14771	   for( i = 0; i < nlinexprs; ++i )
14772	   {
14773	      assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
14774	      auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
14775	   }
14776	
14777	   /* quadratic terms */
14778	   for( i = 0; i < nquadexprs; ++i )
14779	   {
14780	      SCIP_EXPR* quadexprterm;
14781	      SCIP_Real lincoef;
14782	      SCIP_Real sqrcoef;
14783	      SCIP_Real solval;
14784	
14785	      SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
14786	
14787	      assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
14788	
14789	      solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
14790	      auxvalue += (lincoef + sqrcoef * solval) * solval;
14791	   }
14792	
14793	   /* bilinear terms */
14794	   for( i = 0; i < nbilinexprs; ++i )
14795	   {
14796	      SCIP_EXPR* expr1;
14797	      SCIP_EXPR* expr2;
14798	      SCIP_Real coef;
14799	
14800	      SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
14801	
14802	      assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
14803	      assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
14804	      auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
14805	   }
14806	
14807	   return auxvalue;
14808	}
14809	
14810	/**@addtogroup PublicNlhdlrInterfaceMethods
14811	 * @{
14812	 */
14813	
14814	/** creates a nonlinear handler and includes it into the nonlinear constraint handler */
14815	SCIP_RETCODE SCIPincludeNlhdlrNonlinear(
14816	   SCIP*                 scip,               /**< SCIP data structure */
14817	   SCIP_NLHDLR**         nlhdlr,             /**< buffer where to store nonlinear handler */
14818	   const char*           name,               /**< name of nonlinear handler (must not be NULL) */
14819	   const char*           desc,               /**< description of nonlinear handler (can be NULL) */
14820	   int                   detectpriority,     /**< detection priority of nonlinear handler */
14821	   int                   enfopriority,       /**< enforcement priority of nonlinear handler */
14822	   SCIP_DECL_NLHDLRDETECT((*detect)),        /**< structure detection callback of nonlinear handler */
14823	   SCIP_DECL_NLHDLREVALAUX((*evalaux)),      /**< auxiliary evaluation callback of nonlinear handler */
14824	   SCIP_NLHDLRDATA*      nlhdlrdata          /**< data of nonlinear handler (can be NULL) */
14825	   )
14826	{
14827	   SCIP_CONSHDLR* conshdlr;
14828	   SCIP_CONSHDLRDATA* conshdlrdata;
14829	
14830	   assert(scip != NULL);
14831	   assert(nlhdlr != NULL);
14832	   assert(detect != NULL);
14833	
14834	   /* find myself */
14835	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14836	   if( conshdlr == NULL )
14837	   {
14838	      SCIPerrorMessage("nonlinear constraint handler not found");
14839	      return SCIP_PLUGINNOTFOUND;
14840	   }
14841	
14842	   /* create nlhdlr */
14843	   SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
14844	
14845	   /* include into constraint handler */
14846	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
14847	   assert(conshdlrdata != NULL);
14848	
14849	   SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
14850	
14851	   conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
14852	   ++conshdlrdata->nnlhdlrs;
14853	
14854	   /* sort nonlinear handlers by detection priority, in decreasing order
14855	    * will happen in INIT, so only do when called late
14856	    */
14857	   if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
14858	      SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
14859	
14860	   return SCIP_OKAY;
14861	}
14862	
14863	/** get number of nonlinear handler */
14864	int SCIPgetNNlhdlrsNonlinear(
14865	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
14866	   )
14867	{
14868	   SCIP_CONSHDLRDATA* conshdlrdata;
14869	
14870	   assert(conshdlr != NULL);
14871	
14872	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
14873	   assert(conshdlrdata != NULL);
14874	
14875	   return conshdlrdata->nnlhdlrs;
14876	}
14877	
14878	/** get nonlinear handlers */
14879	SCIP_NLHDLR** SCIPgetNlhdlrsNonlinear(
14880	   SCIP_CONSHDLR*        conshdlr            /**< nonlinear constraint handler */
14881	   )
14882	{
14883	   SCIP_CONSHDLRDATA* conshdlrdata;
14884	
14885	   assert(conshdlr != NULL);
14886	
14887	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
14888	   assert(conshdlrdata != NULL);
14889	
14890	   return conshdlrdata->nlhdlrs;
14891	}
14892	
14893	/** returns a nonlinear handler of a given name (or NULL if not found) */
14894	SCIP_NLHDLR* SCIPfindNlhdlrNonlinear(
14895	   SCIP_CONSHDLR*        conshdlr,           /**< nonlinear constraint handler */
14896	   const char*           name                /**< name of nonlinear handler */
14897	   )
14898	{
14899	   SCIP_CONSHDLRDATA* conshdlrdata;
14900	   int h;
14901	
14902	   assert(conshdlr != NULL);
14903	   assert(name != NULL);
14904	
14905	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
14906	   assert(conshdlrdata != NULL);
14907	
14908	   for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
14909	      if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
14910	         return conshdlrdata->nlhdlrs[h];
14911	
14912	   return NULL;
14913	}
14914	
14915	/** gives expression data that a given nonlinear handler stored in an expression
14916	 *
14917	 * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
14918	 */
14919	SCIP_NLHDLREXPRDATA* SCIPgetNlhdlrExprDataNonlinear(
14920	   SCIP_NLHDLR*          nlhdlr,             /**< nonlinear handler */
14921	   SCIP_EXPR*            expr                /**< expression */
14922	   )
14923	{
14924	   SCIP_EXPR_OWNERDATA* ownerdata;
14925	   int e;
14926	
14927	   assert(nlhdlr != NULL);
14928	   assert(expr != NULL);
14929	
14930	   ownerdata = SCIPexprGetOwnerData(expr);
14931	   assert(ownerdata != NULL);
14932	
14933	   for( e = 0; e < ownerdata->nenfos; ++e )
14934	      if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
14935	         return ownerdata->enfos[e]->nlhdlrexprdata;
14936	
14937	   return NULL;
14938	}
14939	
14940	/** @} */
14941