Scippy

SCIP

Solving Constraint Integer Programs

cons_nonlinear.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2022 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_nonlinear.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief constraint handler for nonlinear constraints specified by algebraic expressions
19  * @author Ksenia Bestuzheva
20  * @author Benjamin Mueller
21  * @author Felipe Serrano
22  * @author Stefan Vigerske
23  */
24 
25 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26 
27 #ifdef SCIP_DEBUG
28 #define ENFO_LOGGING
29 #endif
30 
31 /* enable to get log output for enforcement */
32 /* #define ENFO_LOGGING */
33 /* define to get enforcement logging into file */
34 /* #define ENFOLOGFILE "consexpr_enfo.log" */
35 
36 /* define to get more debug output from domain propagation */
37 /* #define DEBUG_PROP */
38 
39 /*lint -e440*/
40 /*lint -e441*/
41 /*lint -e528*/
42 /*lint -e666*/
43 /*lint -e777*/
44 /*lint -e866*/
45 
46 #include <assert.h>
47 #include <ctype.h>
48 
49 #include "scip/cons_nonlinear.h"
50 #include "scip/nlhdlr.h"
51 #include "scip/expr_var.h"
52 #include "scip/expr_sum.h"
53 #include "scip/expr_value.h"
54 #include "scip/expr_pow.h"
55 #include "scip/nlhdlr_convex.h"
56 #include "scip/cons_linear.h"
57 #include "scip/cons_varbound.h"
58 #include "scip/cons_and.h"
60 #include "scip/heur_subnlp.h"
61 #include "scip/heur_trysol.h"
62 #include "scip/nlpi_ipopt.h" /* for SCIPsolveLinearEquationsIpopt */
63 #include "scip/debug.h"
64 #include "scip/dialog_default.h"
65 
66 /* fundamental constraint handler properties */
67 #define CONSHDLR_NAME "nonlinear"
68 #define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
69 #define CONSHDLR_ENFOPRIORITY -60 /**< priority of the constraint handler for constraint enforcing */
70 #define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
71 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
72  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
73 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
74 
75 /* optional constraint handler properties */
76 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
77 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
78 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
79 
80 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
81 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
82 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
83 
84 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
85 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
86 
87 /* properties of the nonlinear constraint handler statistics table */
88 #define TABLE_NAME_NONLINEAR "cons_nonlinear"
89 #define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
90 #define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
91 #define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
92 
93 /* properties of the nonlinear handler statistics table */
94 #define TABLE_NAME_NLHDLR "nlhdlr"
95 #define TABLE_DESC_NLHDLR "nonlinear handler statistics"
96 #define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
97 #define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
98 
99 #define DIALOG_NAME "nlhdlrs"
100 #define DIALOG_DESC "display nonlinear handlers"
101 #define DIALOG_ISSUBMENU FALSE
103 #define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
104 #define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
105 #define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
106 #define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
108 #define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
110 #define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
112 /** translate from one value of infinity to another
113  *
114  * if val is &ge; infty1, then give infty2, else give val
115  */
116 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
118 /** translates x to 2^x for non-negative integer x */
119 #define POWEROFTWO(x) (0x1u << (x))
121 #ifdef ENFO_LOGGING
122 #define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
123 FILE* enfologfile = NULL;
124 #else
125 #define ENFOLOG(x)
126 #endif
127 
128 /*
129  * Data structures
130  */
131 
132 /** enforcement data of an expression */
133 typedef struct
134 {
135  SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
136  SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
137  SCIP_NLHDLR_METHOD nlhdlrparticipation; /**< methods where nonlinear handler participates */
138  SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
139  SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
140  SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
141  SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
143 
144 /** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
145 struct SCIP_Expr_OwnerData
146 {
147  SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
148 
149  /* locks and monotonicity */
150  int nlockspos; /**< positive locks counter */
151  int nlocksneg; /**< negative locks counter */
152  SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
153  int monotonicitysize; /**< length of monotonicity array */
154 
155  /* propagation (in addition to activity that is stored in expr) */
156  SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
157  unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
158  SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
159 
160  /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
161  EXPRENFO** enfos; /**< enforcements */
162  int nenfos; /**< number of enforcements, or -1 if not initialized */
163  unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
164  unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
165  unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
166  unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
167  SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
168 
169  /* branching */
170  SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
171  SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
172  int nviolscores; /**< number of violation scores stored for this expression */
173  unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
174 
175  /* additional data for variable expressions (TODO move into sub-struct?) */
176  SCIP_CONS** conss; /**< constraints in which this variable appears */
177  int nconss; /**< current number of constraints in conss */
178  int consssize; /**< length of conss array */
179  SCIP_Bool consssorted; /**< is the array of constraints sorted */
180 
181  int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
182 };
183 
184 /** constraint data for nonlinear constraints */
185 struct SCIP_ConsData
186 {
187  /* data that defines the constraint: expression and sides */
188  SCIP_EXPR* expr; /**< expression that represents this constraint */
189  SCIP_Real lhs; /**< left-hand side */
190  SCIP_Real rhs; /**< right-hand side */
191 
192  /* variables */
193  SCIP_EXPR** varexprs; /**< array containing all variable expressions */
194  int nvarexprs; /**< total number of variable expressions */
195  SCIP_Bool catchedevents; /**< do we catch events on variables? */
196 
197  /* constraint violation */
198  SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
199  SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
200  SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
201  SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
202 
203  /* status flags */
204  unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
205  unsigned int issimplified:1; /**< did we simplify the expression tree already? */
206 
207  /* locks */
208  int nlockspos; /**< number of positive locks */
209  int nlocksneg; /**< number of negative locks */
210 
211  /* repair infeasible solutions */
212  SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
213  SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
214  SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
215  SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
216 
217  /* miscellaneous */
218  SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
219  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
220  int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
221 };
222 
223 /** constraint upgrade method */
224 typedef struct
225 {
226  SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
227  int priority; /**< priority of upgrading method */
228  SCIP_Bool active; /**< is upgrading enabled */
230 
231 /** constraint handler data */
232 struct SCIP_ConshdlrData
233 {
234  /* nonlinear handler */
235  SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
236  int nnlhdlrs; /**< number of nonlinear handlers */
237  int nlhdlrssize; /**< size of nlhdlrs array */
238  SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
239  SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
240  SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
241 
242  /* constraint upgrades */
243  CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
244  int consupgradessize; /**< size of consupgrades array */
245  int nconsupgrades; /**< number of constraint upgrade methods */
246 
247  /* other plugins */
248  SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
249  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
250  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
251 
252  /* tags and counters */
253  int auxvarid; /**< unique id for the next auxiliary variable */
254  SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
255  SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
256  SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
257  unsigned int enforound; /**< total number of enforcement calls, including current one */
258  int lastconsindex; /**< last used consindex, plus one */
259 
260  /* activity intervals and domain propagation */
261  SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
262  SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
263  SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
264  SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
265  unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
266 
267  /* parameters */
268  int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
269  SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
270  char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
271  SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
272  SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
273  SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
274  SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
275  SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
276  SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
277  SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
278  int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
279  SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
280  SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
281  SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
282  SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
283  SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
284  SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
285  SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
286  SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
287  SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
288  char rownotremovable; /**< whether to make rows to be non-removable in the node where they are added (can prevent some cycling): 'o'ff, in 'e'nforcement only, 'a'lways */
289  char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
290  char checkvarlocks; /**< whether variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction) */
291  int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
292  SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
293  SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
294  SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
295  SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
296  SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
297  SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
298  SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
299  SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
300  char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
301  char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
302  SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
303  char linearizeheursol; /**< whether tight linearizations of nonlinear constraints should be added to cutpool when some heuristics finds a new solution ('o'ff, on new 'i'ncumbents, on 'e'very solution) */
304  SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
305 
306  /* statistics */
307  SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
308  SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
309  SCIP_Longint ndesperatetightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing because we didn't know anything better */
310  SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
311  SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
312  SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
313  SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
314  SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
315 
316  /* facets of envelops of vertex-polyhedral functions */
317  SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
318  SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
319 
320  /* hashing of bilinear terms */
321  SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
322  SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
323  int nbilinterms; /**< total number of bilinear terms */
324  int bilintermssize; /**< size of bilinterms array */
325  int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
326 
327  /* branching */
328  SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
329  char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
330 
331  /* misc */
332  SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
333  SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
334  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
335 };
336 
337 /** branching candidate with various scores */
338 typedef struct
339 {
340  SCIP_EXPR* expr; /**< expression that holds branching candidate */
341  SCIP_Real auxviol; /**< aux-violation score of candidate */
342  SCIP_Real domain; /**< domain score of candidate */
343  SCIP_Real dual; /**< dual score of candidate */
344  SCIP_Real pscost; /**< pseudo-cost score of candidate */
345  SCIP_Real vartype; /**< variable type score of candidate */
346  SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
348 
349 /*
350  * Local methods
351  */
352 
353 /* forward declaration */
354 static
356  SCIP* scip, /**< SCIP data structure */
357  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
358  SCIP_EXPR* rootexpr, /**< expression */
359  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
360  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
361  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
362  );
363 
364 /** frees auxiliary variables of expression, if any */
365 static
367  SCIP* scip, /**< SCIP data structure */
368  SCIP_EXPR* expr /**< expression which auxvar to free, if any */
369  )
370 {
371  SCIP_EXPR_OWNERDATA* mydata;
372 
373  assert(scip != NULL);
374  assert(expr != NULL);
375 
376  mydata = SCIPexprGetOwnerData(expr);
377  assert(mydata != NULL);
378 
379  if( mydata->auxvar == NULL )
380  return SCIP_OKAY;
381 
382  SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
383 
384  /* remove variable locks
385  * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
386  */
387  SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
388 
389  /* release auxiliary variable */
390  SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
391  assert(mydata->auxvar == NULL);
392 
393  return SCIP_OKAY;
394 }
395 
396 /** frees data used for enforcement of expression, that is, nonlinear handlers
397  *
398  * can also clear indicators whether expr needs enforcement methods, that is,
399  * free an associated auxiliary variable and reset the nactivityuses counts
400  */
401 static
403  SCIP* scip, /**< SCIP data structure */
404  SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
405  SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
406  )
407 {
408  SCIP_EXPR_OWNERDATA* mydata;
409  int e;
410 
411  mydata = SCIPexprGetOwnerData(expr);
412  assert(mydata != NULL);
413 
414  if( freeauxvar )
415  {
416  /* free auxiliary variable */
417  SCIP_CALL( freeAuxVar(scip, expr) );
418  assert(mydata->auxvar == NULL);
419 
420  /* reset count on activity and auxvar usage */
421  mydata->nactivityusesprop = 0;
422  mydata->nactivityusessepa = 0;
423  mydata->nauxvaruses = 0;
424  }
425 
426  /* free data stored by nonlinear handlers */
427  for( e = 0; e < mydata->nenfos; ++e )
428  {
429  SCIP_NLHDLR* nlhdlr;
430 
431  assert(mydata->enfos[e] != NULL);
432 
433  nlhdlr = mydata->enfos[e]->nlhdlr;
434  assert(nlhdlr != NULL);
435 
436  if( mydata->enfos[e]->issepainit )
437  {
438  /* call the separation deinitialization callback of the nonlinear handler */
439  SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
440  mydata->enfos[e]->issepainit = FALSE;
441  }
442 
443  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
444  if( mydata->enfos[e]->nlhdlrexprdata != NULL )
445  {
446  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
447  assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
448  }
449 
450  /* free enfo data */
451  SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
452  }
453 
454  /* free array with enfo data */
455  SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
456 
457  /* we need to look at this expression in detect again */
458  mydata->nenfos = -1;
459 
460  return SCIP_OKAY;
461 }
462 
463 /** callback that frees data that this conshdlr stored in an expression */
464 static
465 SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
466 {
467  assert(scip != NULL);
468  assert(expr != NULL);
469  assert(ownerdata != NULL);
470  assert(*ownerdata != NULL);
471 
472  /* expression should not be locked anymore */
473  assert((*ownerdata)->nlockspos == 0);
474  assert((*ownerdata)->nlocksneg == 0);
475 
476  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
477 
478  /* expression should not be enforced anymore */
479  assert((*ownerdata)->nenfos <= 0);
480  assert((*ownerdata)->auxvar == NULL);
481 
482  if( SCIPisExprVar(scip, expr) )
483  {
484  SCIP_CONSHDLRDATA* conshdlrdata;
485  SCIP_VAR* var;
486 
487  /* there should be no constraints left that still use this variable */
488  assert((*ownerdata)->nconss == 0);
489  /* thus, there should also be no variable event catched (via this exprhdlr) */
490  assert((*ownerdata)->filterpos == -1);
491 
492  SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
493 
494  /* update var2expr hashmap in conshdlrdata */
495  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
496  assert(conshdlrdata != NULL);
497 
498  var = SCIPgetVarExprVar(expr);
499  assert(var != NULL);
500 
501  /* remove var -> expr map from hashmap if present
502  * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
503  * if variable-expression stored for var is different, then also do nothing)
504  */
505  if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
506  {
507  SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
508  }
509  }
510 
511  SCIPfreeBlockMemory(scip, ownerdata);
512 
513  return SCIP_OKAY;
514 }
515 
516 static
517 SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
518 { /*lint --e{715}*/
519  assert(ownerdata != NULL);
520 
521  /* print nl handlers associated to expr */
522  if( ownerdata->nenfos > 0 )
523  {
524  int i;
525  SCIPinfoMessage(scip, file, " {");
526 
527  for( i = 0; i < ownerdata->nenfos; ++i )
528  {
529  SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
530  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
531  SCIPinfoMessage(scip, file, "a");
532  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
533  SCIPinfoMessage(scip, file, "u");
534  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
535  SCIPinfoMessage(scip, file, "o");
536  if( i < ownerdata->nenfos-1 )
537  SCIPinfoMessage(scip, file, ", ");
538  }
539 
540  SCIPinfoMessage(scip, file, "}");
541  }
542 
543  /* print aux var associated to expr */
544  if( ownerdata->auxvar != NULL )
545  {
546  SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
547  }
548  SCIPinfoMessage(scip, file, "\n");
549 
550  return SCIP_OKAY;
551 }
552 
553 /** possibly reevaluates and then returns the activity of the expression
554  *
555  * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
556  */
557 static
558 SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
559 {
560  SCIP_CONSHDLRDATA* conshdlrdata;
561 
562  assert(scip != NULL);
563  assert(expr != NULL);
564  assert(ownerdata != NULL);
565 
566  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
567  assert(conshdlrdata != NULL);
568 
569  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
570  {
571  /* update activity of expression */
572  SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
573 
574  assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
575  }
576 
577  return SCIP_OKAY;
578 }
579 
580 /** callback that creates data that this conshdlr wants to store in an expression */
581 static
582 SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
583 {
584  assert(scip != NULL);
585  assert(expr != NULL);
586  assert(ownerdata != NULL);
587 
588  SCIP_CALL( SCIPallocClearBlockMemory(scip, ownerdata) );
589  (*ownerdata)->nenfos = -1;
590  (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
591 
592  if( SCIPisExprVar(scip, expr) )
593  {
594  SCIP_CONSHDLRDATA* conshdlrdata;
595  SCIP_VAR* var;
596 
597  (*ownerdata)->filterpos = -1;
598 
599  /* add to var2expr hashmap if not having expr for var yet */
600 
601  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
602  assert(conshdlrdata != NULL);
603 
604  var = SCIPgetVarExprVar(expr);
605 
606  if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
607  {
608  /* store the variable expression in the hashmap */
609  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
610  }
611  else
612  {
613  /* if expr was just created, then it shouldn't already be stored as image of var */
614  assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
615  }
616  }
617  else
618  {
619  /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
620  (*ownerdata)->filterpos = -2;
621  }
622 
623  *ownerfree = exprownerFree;
624  *ownerprint = exprownerPrint;
625  *ownerevalactivity = exprownerEvalactivity;
626 
627  return SCIP_OKAY;
628 }
629 
630 /** creates a variable expression or retrieves from hashmap in conshdlr data */
631 static
633  SCIP* scip, /**< SCIP data structure */
634  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
635  SCIP_EXPR** expr, /**< pointer where to store expression */
636  SCIP_VAR* var /**< variable to be stored */
637  )
638 {
639  assert(conshdlr != NULL);
640  assert(expr != NULL);
641  assert(var != NULL);
642 
643  /* get variable expression representing the given variable if there is one already */
644  *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
645 
646  if( *expr == NULL )
647  {
648  /* create a new variable expression; this also captures the expression */
649  SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
650  assert(*expr != NULL);
651  /* exprownerCreate should have added var->expr to var2expr */
652  assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
653  }
654  else
655  {
656  /* only capture already existing expr to get a consistent uses-count */
657  SCIPcaptureExpr(*expr);
658  }
659 
660  return SCIP_OKAY;
661 }
662 
663 /* map var exprs to var-expr from var2expr hashmap */
664 static
665 SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
666 { /*lint --e{715}*/
667  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
668 
669  assert(sourcescip != NULL);
670  assert(targetscip != NULL);
671  assert(sourceexpr != NULL);
672  assert(targetexpr != NULL);
673  assert(*targetexpr == NULL);
674  assert(mapexprdata != NULL);
675 
676  /* do not provide map if not variable */
677  if( !SCIPisExprVar(sourcescip, sourceexpr) )
678  return SCIP_OKAY;
679 
680  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
681 
682  return SCIP_OKAY;
683 }
684 
685 /* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
686 static
687 SCIP_DECL_EXPR_MAPEXPR(mapexprtransvar)
688 { /*lint --e{715}*/
689  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
690  SCIP_VAR* var;
691 
692  assert(sourcescip != NULL);
693  assert(targetscip != NULL);
694  assert(sourceexpr != NULL);
695  assert(targetexpr != NULL);
696  assert(*targetexpr == NULL);
697  assert(mapexprdata != NULL);
698 
699  /* do not provide map if not variable */
700  if( !SCIPisExprVar(sourcescip, sourceexpr) )
701  return SCIP_OKAY;
702 
703  var = SCIPgetVarExprVar(sourceexpr);
704  assert(var != NULL);
705 
706  /* transform variable */
707  SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
708  assert(var != NULL);
709 
710  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
711 
712  return SCIP_OKAY;
713 }
714 
715 /** stores all variable expressions into a given constraint */
716 static
718  SCIP* scip, /**< SCIP data structure */
719  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
720  SCIP_CONSDATA* consdata /**< constraint data */
721  )
722 {
723  SCIP_CONSHDLRDATA* conshdlrdata;
724  int varexprssize;
725  int i;
726 
727  assert(consdata != NULL);
728 
729  /* skip if we have stored the variable expressions already */
730  if( consdata->varexprs != NULL )
731  return SCIP_OKAY;
732 
733  assert(consdata->varexprs == NULL);
734  assert(consdata->nvarexprs == 0);
735 
736  /* get an upper bound on number of variable expressions */
737  if( consdata->issimplified )
738  {
739  /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
740  * so we cannot have more variable expression than the number of active variables
741  */
742  varexprssize = SCIPgetNVars(scip);
743  }
744  else
745  {
746  SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
747  }
748 
749  /* create array to store all variable expressions */
750  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
751 
752  SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
753  assert(varexprssize >= consdata->nvarexprs);
754 
755  /* shrink array if there are less variables in the expression than in the problem */
756  if( varexprssize > consdata->nvarexprs )
757  {
758  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
759  }
760 
761  conshdlrdata = SCIPconshdlrGetData(conshdlr);
762  assert(conshdlrdata != NULL);
763  assert(conshdlrdata->var2expr != NULL);
764 
765  /* ensure that for every variable an entry exists in the var2expr hashmap
766  * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
767  */
768  for( i = 0; i < consdata->nvarexprs; ++i )
769  {
770  if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
771  {
772  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
773  }
774  }
775 
776  return SCIP_OKAY;
777 }
778 
779 /** frees all variable expression stored in storeVarExprs() */
780 static
782  SCIP* scip, /**< SCIP data structure */
783  SCIP_CONSDATA* consdata /**< constraint data */
784  )
785 {
786  int i;
787 
788  assert(consdata != NULL);
789 
790  /* skip if we have stored the variable expressions already*/
791  if( consdata->varexprs == NULL )
792  return SCIP_OKAY;
793 
794  assert(consdata->varexprs != NULL);
795  assert(consdata->nvarexprs >= 0);
796 
797  /* release variable expressions */
798  for( i = 0; i < consdata->nvarexprs; ++i )
799  {
800  assert(consdata->varexprs[i] != NULL);
801  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
802  assert(consdata->varexprs[i] == NULL);
803  }
804 
805  /* free variable expressions */
806  SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
807  consdata->varexprs = NULL;
808  consdata->nvarexprs = 0;
809 
810  return SCIP_OKAY;
811 }
812 
813 /** interval evaluation of variables as used in bound tightening
814  *
815  * Returns slightly relaxed local variable bounds of a variable as interval.
816  * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
817  */
818 static
819 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
820 {
821  SCIP_INTERVAL interval;
822  SCIP_CONSHDLRDATA* conshdlrdata;
823  SCIP_Real lb;
824  SCIP_Real ub;
825 
826  assert(scip != NULL);
827  assert(var != NULL);
828 
829  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
830  assert(conshdlrdata != NULL);
831 
832  if( conshdlrdata->globalbounds )
833  {
834  lb = SCIPvarGetLbGlobal(var);
835  ub = SCIPvarGetUbGlobal(var);
836  }
837  else
838  {
839  lb = SCIPvarGetLbLocal(var);
840  ub = SCIPvarGetUbLocal(var);
841  }
842  assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
843 
844  /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
846  {
847  lb = EPSROUND(lb, 0.0); /*lint !e835*/
848  ub = EPSROUND(ub, 0.0); /*lint !e835*/
849  }
850 
851  /* integer variables should always have integral bounds in SCIP */
852  assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
853  assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
854 
855  switch( conshdlrdata->varboundrelax )
856  {
857  case 'n' : /* no relaxation */
858  break;
859 
860  case 'a' : /* relax by absolute value */
861  {
862  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
863  if( SCIPvarIsIntegral(var) )
864  break;
865 
866  if( !SCIPisInfinity(scip, -lb) )
867  {
868  /* reduce lb by epsilon, or to the next integer value, which ever is larger */
869  SCIP_Real bnd = floor(lb);
870  lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
871  }
872 
873  if( !SCIPisInfinity(scip, ub) )
874  {
875  /* increase ub by epsilon, or to the next integer value, which ever is smaller */
876  SCIP_Real bnd = ceil(ub);
877  ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
878  }
879 
880  break;
881  }
882 
883  case 'b' : /* relax always by absolute value */
884  {
885  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
886  if( SCIPvarIsIntegral(var) )
887  break;
888 
889  if( !SCIPisInfinity(scip, -lb) )
890  lb -= conshdlrdata->varboundrelaxamount;
891 
892  if( !SCIPisInfinity(scip, ub) )
893  ub += conshdlrdata->varboundrelaxamount;
894 
895  break;
896  }
897 
898  case 'r' : /* relax by relative value */
899  {
900  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
901  if( SCIPvarIsIntegral(var) )
902  break;
903 
904  /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
905  * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
906  * further, do not relax beyond next integer value
907  */
908  if( !SCIPisInfinity(scip, -lb) )
909  {
910  SCIP_Real bnd = floor(lb);
911  lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
912  }
913 
914  if( !SCIPisInfinity(scip, ub) )
915  {
916  SCIP_Real bnd = ceil(ub);
917  ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
918  }
919 
920  break;
921  }
922 
923  default :
924  {
925  SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
926  SCIPABORT();
927  break;
928  }
929  }
930 
931  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
934  assert(lb <= ub);
935 
936  SCIPintervalSetBounds(&interval, lb, ub);
937 
938  return interval;
939 }
940 
941 /** compares two nonlinear constraints by its index
942  *
943  * Usable as compare operator in array sort functions.
944  */
945 static
946 SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
947 {
948  SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
949  SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
950 
951  assert(consdata1 != NULL);
952  assert(consdata2 != NULL);
953 
954  return consdata1->consindex - consdata2->consindex;
955 }
956 
957 /** processes variable fixing or bound change event */
958 static
959 SCIP_DECL_EVENTEXEC(processVarEvent)
960 { /*lint --e{715}*/
961  SCIP_EVENTTYPE eventtype;
962  SCIP_EXPR* expr;
963  SCIP_EXPR_OWNERDATA* ownerdata;
964 
965  eventtype = SCIPeventGetType(event);
967 
968  assert(eventdata != NULL);
969  expr = (SCIP_EXPR*) eventdata;
970  assert(SCIPisExprVar(scip, expr));
971 
972  SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
976 
977  ownerdata = SCIPexprGetOwnerData(expr);
978  assert(ownerdata != NULL);
979  /* we only catch varevents for variables in constraints, so there should be constraints */
980  assert(ownerdata->nconss > 0);
981  assert(ownerdata->conss != NULL);
982 
983  /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
984  * - propagation can only find something new if a bound was tightened
985  * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
986  * and we look at global changes (that is, we are not looking at boundchanges in probing)
987  */
989  {
990  SCIP_CONSDATA* consdata;
991  int c;
992 
993  for( c = 0; c < ownerdata->nconss; ++c )
994  {
995  assert(ownerdata->conss[c] != NULL);
996  consdata = SCIPconsGetData(ownerdata->conss[c]);
997 
998  /* if bound tightening, then mark constraints to be propagated again
999  * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1000  * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1001  * the locks don't help since they are not available separately for each constraint
1002  */
1003  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1004  {
1005  consdata->ispropagated = FALSE;
1006  SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1007  }
1008 
1009  /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1010  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !SCIPinProbing(scip) )
1011  {
1012  consdata->issimplified = FALSE;
1013  SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1014  }
1015  }
1016  }
1017 
1018  /* update curboundstag, lastboundrelax, and expr activity */
1019  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1020  {
1021  SCIP_CONSHDLRDATA* conshdlrdata;
1022  SCIP_INTERVAL activity;
1023 
1024  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1025  assert(conshdlrdata != NULL);
1026 
1027  /* increase tag on bounds */
1028  ++conshdlrdata->curboundstag;
1029  assert(conshdlrdata->curboundstag > 0);
1030 
1031  /* remember also if we relaxed bounds now */
1032  if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1033  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1034 
1035  /* update the activity of the var-expr here immediately
1036  * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1037  */
1038  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1039  /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1040 #ifdef DEBUG_PROP
1041  SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1042 #endif
1043  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1044  }
1045 
1046  return SCIP_OKAY;
1047 }
1048 
1049 /** registers event handler to catch variable events on variable
1050  *
1051  * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1052  * When an event occurs, all stored constraints are notified.
1053  */
1054 static
1056  SCIP* scip, /**< SCIP data structure */
1057  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1058  SCIP_EXPR* expr, /**< variable expression */
1059  SCIP_CONS* cons /**< nonlinear constraint */
1060  )
1061 {
1062  SCIP_EXPR_OWNERDATA* ownerdata;
1063 
1064  assert(eventhdlr != NULL);
1065  assert(expr != NULL);
1066  assert(SCIPisExprVar(scip, expr));
1067  assert(cons != NULL);
1068 
1069  ownerdata = SCIPexprGetOwnerData(expr);
1070  assert(ownerdata != NULL);
1071 
1072 #ifndef NDEBUG
1073  /* assert that constraint does not double-catch variable */
1074  {
1075  int i;
1076  for( i = 0; i < ownerdata->nconss; ++i )
1077  assert(ownerdata->conss[i] != cons);
1078  }
1079 #endif
1080 
1081  /* append cons to ownerdata->conss */
1082  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1083  ownerdata->conss[ownerdata->nconss++] = cons;
1084  /* we're not capturing the constraint here to avoid circular references */
1085 
1086  /* updated sorted flag */
1087  if( ownerdata->nconss <= 1 )
1088  ownerdata->consssorted = TRUE;
1089  else if( ownerdata->consssorted )
1090  ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1091 
1092  /* catch variable events, if not done so yet (first constraint) */
1093  if( ownerdata->filterpos < 0 )
1094  {
1095  SCIP_EVENTTYPE eventtype;
1096 
1097  assert(ownerdata->nconss == 1);
1098 
1100 
1101  SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1102  assert(ownerdata->filterpos >= 0);
1103  }
1104 
1105  return SCIP_OKAY;
1106 }
1107 
1108 /** catch variable events */
1109 static
1111  SCIP* scip, /**< SCIP data structure */
1112  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1113  SCIP_CONS* cons /**< constraint for which to catch bound change events */
1114  )
1115 {
1116  SCIP_CONSHDLRDATA* conshdlrdata;
1117  SCIP_CONSDATA* consdata;
1118  SCIP_EXPR* expr;
1119  int i;
1120 
1121  assert(eventhdlr != NULL);
1122  assert(cons != NULL);
1123 
1124  consdata = SCIPconsGetData(cons);
1125  assert(consdata != NULL);
1126  assert(consdata->varexprs != NULL);
1127  assert(consdata->nvarexprs >= 0);
1128 
1129  /* check if we have catched variable events already */
1130  if( consdata->catchedevents )
1131  return SCIP_OKAY;
1132 
1133  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1134  assert(conshdlrdata != NULL);
1135  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1136 
1137  SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1138 
1139  for( i = 0; i < consdata->nvarexprs; ++i )
1140  {
1141  expr = consdata->varexprs[i];
1142 
1143  assert(expr != NULL);
1144  assert(SCIPisExprVar(scip, expr));
1145 
1146  SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1147 
1148  /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1149  * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1150  */
1151  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1152  {
1153  SCIP_INTERVAL activity;
1154  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1155  /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1156  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1157 #ifdef DEBUG_PROP
1158  SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1159 #endif
1160  }
1161  }
1162 
1163  consdata->catchedevents = TRUE;
1164 
1165  return SCIP_OKAY;
1166 }
1167 
1168 /** unregisters event handler to catch variable events on variable
1169  *
1170  * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1171  * If this was the last constraint, then the event handler is unregistered for this variable.
1172  */
1173 static
1175  SCIP* scip, /**< SCIP data structure */
1176  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1177  SCIP_EXPR* expr, /**< variable expression */
1178  SCIP_CONS* cons /**< expr constraint */
1179  )
1180 {
1181  SCIP_EXPR_OWNERDATA* ownerdata;
1182  int pos;
1183 
1184  assert(eventhdlr != NULL);
1185  assert(expr != NULL);
1186  assert(SCIPisExprVar(scip, expr));
1187  assert(cons != NULL);
1188 
1189  ownerdata = SCIPexprGetOwnerData(expr);
1190  assert(ownerdata != NULL);
1191  assert(ownerdata->nconss > 0);
1192 
1193  if( ownerdata->conss[ownerdata->nconss-1] == cons )
1194  {
1195  pos = ownerdata->nconss-1;
1196  }
1197  else
1198  {
1199  if( !ownerdata->consssorted )
1200  {
1201  SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1202  ownerdata->consssorted = TRUE;
1203  }
1204 
1205  if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1206  {
1207  SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1208  return SCIP_ERROR;
1209  }
1210  assert(pos >= 0 && pos < ownerdata->nconss);
1211  }
1212  assert(ownerdata->conss[pos] == cons);
1213 
1214  /* move last constraint into position of removed constraint */
1215  if( pos < ownerdata->nconss-1 )
1216  {
1217  ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1218  ownerdata->consssorted = FALSE;
1219  }
1220  --ownerdata->nconss;
1221 
1222  /* drop variable events if that was the last constraint */
1223  if( ownerdata->nconss == 0 )
1224  {
1225  SCIP_EVENTTYPE eventtype;
1226 
1227  assert(ownerdata->filterpos >= 0);
1228 
1230 
1231  SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1232  ownerdata->filterpos = -1;
1233  }
1234 
1235  return SCIP_OKAY;
1236 }
1237 
1238 /** drop variable events */
1239 static
1241  SCIP* scip, /**< SCIP data structure */
1242  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1243  SCIP_CONS* cons /**< constraint for which to drop bound change events */
1244  )
1245 {
1246  SCIP_CONSDATA* consdata;
1247  int i;
1248 
1249  assert(eventhdlr != NULL);
1250  assert(cons != NULL);
1251 
1252  consdata = SCIPconsGetData(cons);
1253  assert(consdata != NULL);
1254 
1255  /* check if we have catched variable events already */
1256  if( !consdata->catchedevents )
1257  return SCIP_OKAY;
1258 
1259  assert(consdata->varexprs != NULL);
1260  assert(consdata->nvarexprs >= 0);
1261 
1262  SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1263 
1264  for( i = consdata->nvarexprs - 1; i >= 0; --i )
1265  {
1266  assert(consdata->varexprs[i] != NULL);
1267 
1268  SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1269  }
1270 
1271  consdata->catchedevents = FALSE;
1272 
1273  return SCIP_OKAY;
1274 }
1275 
1276 /** creates and captures a nonlinear constraint
1277  *
1278  * @attention Use copyexpr=FALSE only if expr is already "owned" by conshdlr, that is, if expressions were created with exprownerCreate() and ownerdata passed in the last two arguments
1279  */
1280 static
1282  SCIP* scip, /**< SCIP data structure */
1283  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1284  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1285  const char* name, /**< name of constraint */
1286  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1287  SCIP_Real lhs, /**< left hand side of constraint */
1288  SCIP_Real rhs, /**< right hand side of constraint */
1289  SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1290  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1291  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1292  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1293  * Usually set to TRUE. */
1294  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1295  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1296  SCIP_Bool check, /**< should the constraint be checked for feasibility?
1297  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1298  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1299  * Usually set to TRUE. */
1300  SCIP_Bool local, /**< is constraint only valid locally?
1301  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1302  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1303  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1304  * adds coefficients to this constraint. */
1305  SCIP_Bool dynamic, /**< is constraint subject to aging?
1306  * Usually set to FALSE. Set to TRUE for own cuts which
1307  * are separated as constraints. */
1308  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1309  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1310  )
1311 {
1312  SCIP_CONSHDLRDATA* conshdlrdata;
1313  SCIP_CONSDATA* consdata;
1314 
1315  assert(conshdlr != NULL);
1316  assert(expr != NULL);
1317 
1318  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1319  assert(conshdlrdata != NULL);
1320 
1321  if( local && SCIPgetDepth(scip) != 0 )
1322  {
1323  SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1324  return SCIP_INVALIDCALL;
1325  }
1326 
1327  /* TODO we should allow for non-initial nonlinear constraints */
1328  if( !initial )
1329  {
1330  SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1331  return SCIP_INVALIDCALL;
1332  }
1333 
1334  /* create constraint data */
1335  SCIP_CALL( SCIPallocClearBlockMemory(scip, &consdata) );
1336 
1337  if( copyexpr )
1338  {
1339  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1340  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1341  }
1342  else
1343  {
1344  consdata->expr = expr;
1345  SCIPcaptureExpr(consdata->expr);
1346  }
1347  consdata->lhs = lhs;
1348  consdata->rhs = rhs;
1349  consdata->consindex = conshdlrdata->lastconsindex++;
1350  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1351 
1352  /* create constraint */
1353  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1354  local, modifiable, dynamic, removable, FALSE) );
1355 
1356  return SCIP_OKAY;
1357 }
1358 
1359 /** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1360  *
1361  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1362  * Assume that f(x) is associated with auxiliary variable z.
1363  *
1364  * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1365  * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1366  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1367  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1368  *
1369  * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1370  */
1371 static
1373  SCIP* scip, /**< SCIP data structure */
1374  SCIP_EXPR* expr, /**< expression */
1375  SCIP_SOL* sol, /**< solution that has been evaluated */
1376  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1377  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1378  )
1379 {
1380  SCIP_EXPR_OWNERDATA* ownerdata;
1381  SCIP_Real auxvarvalue;
1382 
1383  assert(expr != NULL);
1384 
1385  ownerdata = SCIPexprGetOwnerData(expr);
1386  assert(ownerdata != NULL);
1387  assert(ownerdata->auxvar != NULL);
1388 
1389  if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1390  {
1391  if( violunder != NULL )
1392  *violunder = TRUE;
1393  if( violover != NULL )
1394  *violover = TRUE;
1395  return SCIPinfinity(scip);
1396  }
1397 
1398  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1399 
1400  if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1401  {
1402  if( violunder != NULL )
1403  *violunder = FALSE;
1404  if( violover != NULL )
1405  *violover = TRUE;
1406  return auxvarvalue - SCIPexprGetEvalValue(expr);
1407  }
1408 
1409  if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1410  {
1411  if( violunder != NULL )
1412  *violunder = TRUE;
1413  if( violover != NULL )
1414  *violover = FALSE;
1415  return SCIPexprGetEvalValue(expr) - auxvarvalue;
1416  }
1417 
1418  if( violunder != NULL )
1419  *violunder = FALSE;
1420  if( violover != NULL )
1421  *violover = FALSE;
1422  return 0.0;
1423 }
1424 
1425 /** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1426  *
1427  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1428  * Assume that f(w) is associated with auxiliary variable z.
1429  *
1430  * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1431  * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1432  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1433  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1434  *
1435  * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1436  */
1437 static
1439  SCIP* scip, /**< SCIP data structure */
1440  SCIP_EXPR* expr, /**< expression */
1441  SCIP_Real auxvalue, /**< value of f(w) */
1442  SCIP_SOL* sol, /**< solution that has been evaluated */
1443  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1444  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1445  )
1446 {
1447  SCIP_EXPR_OWNERDATA* ownerdata;
1448  SCIP_Real auxvarvalue;
1449 
1450  assert(expr != NULL);
1451 
1452  ownerdata = SCIPexprGetOwnerData(expr);
1453  assert(ownerdata != NULL);
1454  assert(ownerdata->auxvar != NULL);
1455 
1456  if( auxvalue == SCIP_INVALID )
1457  {
1458  if( violunder != NULL )
1459  *violunder = TRUE;
1460  if( violover != NULL )
1461  *violover = TRUE;
1462  return SCIPinfinity(scip);
1463  }
1464 
1465  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1466 
1467  if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1468  {
1469  if( violunder != NULL )
1470  *violunder = FALSE;
1471  if( violover != NULL )
1472  *violover = TRUE;
1473  return auxvarvalue - auxvalue;
1474  }
1475 
1476  if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1477  {
1478  if( violunder != NULL )
1479  *violunder = TRUE;
1480  if( violover != NULL )
1481  *violover = FALSE;
1482  return auxvalue - auxvarvalue;
1483  }
1484 
1485  if( violunder != NULL )
1486  *violunder = FALSE;
1487  if( violover != NULL )
1488  *violover = FALSE;
1489 
1490  return 0.0;
1491 }
1492 
1493 /** computes violation of a constraint */
1494 static
1496  SCIP* scip, /**< SCIP data structure */
1497  SCIP_CONS* cons, /**< constraint */
1498  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1499  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1500  )
1501 {
1502  SCIP_CONSDATA* consdata;
1503  SCIP_Real activity;
1504 
1505  assert(scip != NULL);
1506  assert(cons != NULL);
1507 
1508  consdata = SCIPconsGetData(cons);
1509  assert(consdata != NULL);
1510 
1511  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1512  activity = SCIPexprGetEvalValue(consdata->expr);
1513 
1514  /* consider constraint as violated if it is undefined in the current point */
1515  if( activity == SCIP_INVALID )
1516  {
1517  consdata->lhsviol = SCIPinfinity(scip);
1518  consdata->rhsviol = SCIPinfinity(scip);
1519  return SCIP_OKAY;
1520  }
1521 
1522  /* compute violations */
1523  consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1524  consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1525 
1526  return SCIP_OKAY;
1527 }
1528 
1529 /** returns absolute violation of a constraint
1530  *
1531  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1532  */
1533 static
1535  SCIP_CONS* cons /**< constraint */
1536  )
1537 {
1538  SCIP_CONSDATA* consdata;
1539 
1540  assert(cons != NULL);
1541 
1542  consdata = SCIPconsGetData(cons);
1543  assert(consdata != NULL);
1544 
1545  return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1546 }
1547 
1548 /** computes relative violation of a constraint
1549  *
1550  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1551  */
1552 static
1554  SCIP* scip, /**< SCIP data structure */
1555  SCIP_CONS* cons, /**< constraint */
1556  SCIP_Real* viol, /**< buffer to store violation */
1557  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1558  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1559  )
1560 {
1561  SCIP_CONSHDLR* conshdlr;
1562  SCIP_CONSHDLRDATA* conshdlrdata;
1563  SCIP_CONSDATA* consdata;
1564  SCIP_Real scale;
1565 
1566  assert(cons != NULL);
1567  assert(viol != NULL);
1568 
1569  conshdlr = SCIPconsGetHdlr(cons);
1570  assert(conshdlr != NULL);
1571 
1572  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1573  assert(conshdlrdata != NULL);
1574 
1575  *viol = getConsAbsViolation(cons);
1576 
1577  if( conshdlrdata->violscale == 'n' )
1578  return SCIP_OKAY;
1579 
1580  if( SCIPisInfinity(scip, *viol) )
1581  return SCIP_OKAY;
1582 
1583  consdata = SCIPconsGetData(cons);
1584  assert(consdata != NULL);
1585 
1586  if( conshdlrdata->violscale == 'a' )
1587  {
1588  scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1589 
1590  /* consider value of side that is violated for scaling, too */
1591  if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1592  {
1593  assert(!SCIPisInfinity(scip, -consdata->lhs));
1594  scale = REALABS(consdata->lhs);
1595  }
1596  else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1597  {
1598  assert(!SCIPisInfinity(scip, consdata->rhs));
1599  scale = REALABS(consdata->rhs);
1600  }
1601 
1602  *viol /= scale;
1603  return SCIP_OKAY;
1604  }
1605 
1606  /* if not 'n' or 'a', then it has to be 'g' at the moment */
1607  assert(conshdlrdata->violscale == 'g');
1608  if( soltag == 0L || consdata->gradnormsoltag != soltag )
1609  {
1610  /* we need the varexprs to conveniently access the gradient */
1611  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1612 
1613  /* update cached value of norm of gradient */
1614  consdata->gradnorm = 0.0;
1615 
1616  /* compute gradient */
1617  SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1618 
1619  /* gradient evaluation error -> no scaling */
1620  if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1621  {
1622  int i;
1623  for( i = 0; i < consdata->nvarexprs; ++i )
1624  {
1625  SCIP_Real deriv;
1626 
1627  assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1628  deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1629  if( deriv == SCIP_INVALID )
1630  {
1631  /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1632  consdata->gradnorm = 0.0;
1633  break;
1634  }
1635 
1636  consdata->gradnorm += deriv*deriv;
1637  }
1638  }
1639  consdata->gradnorm = sqrt(consdata->gradnorm);
1640  consdata->gradnormsoltag = soltag;
1641  }
1642 
1643  *viol /= MAX(1.0, consdata->gradnorm);
1644 
1645  return SCIP_OKAY;
1646 }
1647 
1648 /** returns whether constraint is currently violated
1649  *
1650  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1651  */
1652 static
1654  SCIP* scip, /**< SCIP data structure */
1655  SCIP_CONS* cons /**< constraint */
1656  )
1657 {
1658  return getConsAbsViolation(cons) > SCIPfeastol(scip);
1659 }
1660 
1661 /** checks for a linear variable that can be increased or decreased without harming feasibility */
1662 static
1664  SCIP* scip, /**< SCIP data structure */
1665  SCIP_CONS* cons /**< constraint */
1666  )
1667 {
1668  SCIP_CONSDATA* consdata;
1669  int poslock;
1670  int neglock;
1671  int i;
1672 
1673  assert(cons != NULL);
1674 
1675  consdata = SCIPconsGetData(cons);
1676  assert(consdata != NULL);
1677 
1678  consdata->linvarincr = NULL;
1679  consdata->linvardecr = NULL;
1680  consdata->linvarincrcoef = 0.0;
1681  consdata->linvardecrcoef = 0.0;
1682 
1683  /* root expression is not a sum -> no unlocked linear variable available */
1684  if( !SCIPisExprSum(scip, consdata->expr) )
1685  return;
1686 
1687  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1688  {
1689  SCIP_EXPR* child;
1690 
1691  child = SCIPexprGetChildren(consdata->expr)[i];
1692  assert(child != NULL);
1693 
1694  /* check whether the child is a variable expression */
1695  if( SCIPisExprVar(scip, child) )
1696  {
1697  SCIP_VAR* var = SCIPgetVarExprVar(child);
1698  SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1699 
1700  if( coef > 0.0 )
1701  {
1702  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1703  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1704  }
1705  else
1706  {
1707  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1708  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1709  }
1711 
1712  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1713  {
1714  /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1715  * if we have already one candidate, then take the one where the loss in the objective function is less
1716  */
1717  if( (consdata->linvardecr == NULL) ||
1718  (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1719  {
1720  consdata->linvardecr = var;
1721  consdata->linvardecrcoef = coef;
1722  }
1723  }
1724 
1725  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1726  {
1727  /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1728  * if we have already one candidate, then take the one where the loss in the objective function is less
1729  */
1730  if( (consdata->linvarincr == NULL) ||
1731  (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1732  {
1733  consdata->linvarincr = var;
1734  consdata->linvarincrcoef = coef;
1735  }
1736  }
1737  }
1738  }
1739 
1740  assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1741  assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1742 
1743  if( consdata->linvarincr != NULL )
1744  {
1745  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1746  }
1747  if( consdata->linvardecr != NULL )
1748  {
1749  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1750  }
1751 }
1752 
1753 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1754  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1755  *
1756  * The method assumes that this is always possible and that not all constraints are feasible already.
1757  */
1758 static
1760  SCIP* scip, /**< SCIP data structure */
1761  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1762  SCIP_CONS** conss, /**< constraints to process */
1763  int nconss, /**< number of constraints */
1764  SCIP_SOL* sol, /**< solution to process */
1765  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1766  )
1767 {
1768  SCIP_CONSHDLRDATA* conshdlrdata;
1769  SCIP_SOL* newsol;
1770  int c;
1771 
1772  assert(scip != NULL);
1773  assert(conshdlr != NULL);
1774  assert(conss != NULL || nconss == 0);
1775  assert(success != NULL);
1776 
1777  *success = FALSE;
1778 
1779  /* don't propose new solutions if not in presolve or solving */
1781  return SCIP_OKAY;
1782 
1783  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1784  assert(conshdlrdata != NULL);
1785 
1786  if( sol != NULL )
1787  {
1788  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1789  }
1790  else
1791  {
1792  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1793  }
1794  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1795  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1796  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1797 
1798  for( c = 0; c < nconss; ++c )
1799  {
1800  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1801  SCIP_Real viol = 0.0;
1802  SCIP_Real delta;
1803  SCIP_Real gap;
1804 
1805  assert(consdata != NULL);
1806 
1807  /* get absolute violation and sign */
1808  if( consdata->lhsviol > SCIPfeastol(scip) )
1809  viol = consdata->lhsviol; /* lhs - activity */
1810  else if( consdata->rhsviol > SCIPfeastol(scip) )
1811  viol = -consdata->rhsviol; /* rhs - activity */
1812  else
1813  continue; /* constraint is satisfied */
1814 
1815  if( consdata->linvarincr != NULL &&
1816  ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1817  {
1818  SCIP_VAR* var = consdata->linvarincr;
1819 
1820  /* compute how much we would like to increase var */
1821  delta = viol / consdata->linvarincrcoef;
1822  assert(delta > 0.0);
1823 
1824  /* if var has an upper bound, may need to reduce delta */
1825  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1826  {
1827  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1828  delta = MIN(MAX(0.0, gap), delta);
1829  }
1830  if( SCIPisPositive(scip, delta) )
1831  {
1832  /* if variable is integral, round delta up so that it will still have an integer value */
1833  if( SCIPvarIsIntegral(var) )
1834  delta = SCIPceil(scip, delta);
1835 
1836  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1837  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1838  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1839 
1840  /* adjust constraint violation, if satisfied go on to next constraint */
1841  viol -= consdata->linvarincrcoef * delta;
1842  if( SCIPisZero(scip, viol) )
1843  continue;
1844  }
1845  }
1846 
1847  assert(viol != 0.0);
1848  if( consdata->linvardecr != NULL &&
1849  ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1850  {
1851  SCIP_VAR* var = consdata->linvardecr;
1852 
1853  /* compute how much we would like to decrease var */
1854  delta = viol / consdata->linvardecrcoef;
1855  assert(delta < 0.0);
1856 
1857  /* if var has a lower bound, may need to reduce delta */
1858  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
1859  {
1860  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1861  delta = MAX(MIN(0.0, gap), delta);
1862  }
1863  if( SCIPisNegative(scip, delta) )
1864  {
1865  /* if variable is integral, round delta down so that it will still have an integer value */
1866  if( SCIPvarIsIntegral(var) )
1867  delta = SCIPfloor(scip, delta);
1868  SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1869  /*lint --e{613} */
1870  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1871  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1872 
1873  /* adjust constraint violation, if satisfied go on to next constraint */
1874  viol -= consdata->linvardecrcoef * delta;
1875  if( SCIPisZero(scip, viol) )
1876  continue;
1877  }
1878  }
1879 
1880  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1881  break;
1882  }
1883 
1884  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1885  * then pass it to the trysol heuristic
1886  */
1887  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1888  {
1889  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1890 
1891  assert(conshdlrdata->trysolheur != NULL);
1892  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1893 
1894  *success = TRUE;
1895  }
1896 
1897  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1898 
1899  return SCIP_OKAY;
1900 }
1901 
1902 /** adds globally valid tight estimators in a given solution as cut to cutpool
1903  *
1904  * Called by addTightEstimatorCuts() for a specific expression, nlhdlr, and estimate-direction (over or under).
1905  */
1906 static
1908  SCIP* scip, /**< SCIP data structure */
1909  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1910  SCIP_CONS* cons, /**< constraint */
1911  SCIP_EXPR* expr, /**< expression */
1912  EXPRENFO* exprenfo, /**< expression enfo data, e.g., nlhdlr to use */
1913  SCIP_SOL* sol, /**< reference point where to estimate */
1914  SCIP_Bool overestimate, /**< whether to overestimate */
1915  SCIP_PTRARRAY* rowpreps /**< array for rowpreps */
1916  )
1917 {
1918  SCIP_Bool estimatesuccess = FALSE;
1919  SCIP_Bool branchscoresuccess = FALSE;
1920  int minidx;
1921  int maxidx;
1922  int r;
1923 
1924  assert(scip != NULL);
1925  assert(expr != NULL);
1926  assert(exprenfo != NULL);
1927  assert(rowpreps != NULL);
1928 
1929  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %sestimate using nlhdlr <%s> for expr %p (%s)\n",
1930  overestimate ? "over" : "under", SCIPnlhdlrGetName(exprenfo->nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))); )
1931 
1932  SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, exprenfo->nlhdlr, expr, exprenfo->nlhdlrexprdata, sol,
1933  exprenfo->auxvalue, overestimate, overestimate ? SCIPinfinity(scip) : -SCIPinfinity(scip), FALSE, rowpreps, &estimatesuccess, &branchscoresuccess) );
1934 
1935  minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
1936  maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
1937  assert(estimatesuccess == (minidx <= maxidx));
1938 
1939  if( !estimatesuccess )
1940  {
1941  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n", SCIPnlhdlrGetName(exprenfo->nlhdlr)); )
1942  return SCIP_OKAY;
1943  }
1944 
1945  for( r = minidx; r <= maxidx; ++r )
1946  {
1947  SCIP_ROWPREP* rowprep;
1948  SCIP_ROW* row;
1949  SCIP_Real estimateval;
1950  int i;
1951 
1952  rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
1953  assert(rowprep != NULL);
1954  assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
1955 
1956  /* if estimators is only local valid, then skip */
1957  if( SCIProwprepIsLocal(rowprep) )
1958  {
1959  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip local estimator\n"); )
1960  SCIPfreeRowprep(scip, &rowprep);
1961  continue;
1962  }
1963 
1964  /* compute value of estimator */
1965  estimateval = -SCIProwprepGetSide(rowprep);
1966  for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
1967  estimateval += SCIProwprepGetCoefs(rowprep)[i] * SCIPgetSolVal(scip, sol, SCIProwprepGetVars(rowprep)[i]);
1968 
1969  /* if estimator value is not tight (or even "more than tight", e.g., when estimating in integer vars), then skip */
1970  if( (overestimate && !SCIPisFeasLE(scip, estimateval, SCIPexprGetEvalValue(expr))) ||
1971  (!overestimate && !SCIPisFeasGE(scip, estimateval, SCIPexprGetEvalValue(expr))) )
1972  {
1973  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip non-tight estimator with value %g, expr value %g\n", estimateval, SCIPexprGetEvalValue(expr)); )
1974  SCIPfreeRowprep(scip, &rowprep);
1975  continue;
1976  }
1977 
1978  /* complete estimator to cut and clean it up */
1979  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
1980  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPinfinity(scip), &estimatesuccess) );
1981 
1982  /* if cleanup failed or rowprep is local now, then skip */
1983  if( !estimatesuccess || SCIProwprepIsLocal(rowprep) )
1984  {
1985  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip after cleanup failed or made estimator locally valid\n"); )
1986  SCIPfreeRowprep(scip, &rowprep);
1987  continue;
1988  }
1989 
1990  /* generate row and add to cutpool */
1991  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
1992 
1993  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
1994  SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
1995 
1996  SCIP_CALL( SCIPaddPoolCut(scip, row) );
1997  /* SCIPnlhdlrIncrementNSeparated(nlhdlr); */
1998 
1999  SCIP_CALL( SCIPreleaseRow(scip, &row) );
2000  SCIPfreeRowprep(scip, &rowprep);
2001  }
2002 
2003  SCIP_CALL( SCIPclearPtrarray(scip, rowpreps) );
2004 
2005  return SCIP_OKAY;
2006 }
2007 
2008 /** adds globally valid tight estimators in a given solution as cuts to cutpool
2009  *
2010  * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
2011  * For convex constraints, we would achieve this by linearizing.
2012  * To avoid checking explicitly for convexity, we compute estimators via any nlhdlr that didn't say it would
2013  * use bound information and check whether the estimator is tight.
2014  *
2015  * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
2016  * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
2017  */
2018 static
2020  SCIP* scip, /**< SCIP data structure */
2021  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2022  SCIP_CONS** conss, /**< constraints */
2023  int nconss, /**< number of constraints */
2024  SCIP_SOL* sol /**< reference point where to estimate */
2025  )
2026 {
2027  SCIP_CONSDATA* consdata;
2028  SCIP_Longint soltag;
2029  SCIP_EXPRITER* it;
2030  SCIP_EXPR* expr;
2031  SCIP_PTRARRAY* rowpreps;
2032  int c, e;
2033 
2034  assert(scip != NULL);
2035  assert(conshdlr != NULL);
2036  assert(conss != NULL || nconss == 0);
2037 
2038  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "add tight estimators in new solution from <%s> to cutpool\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
2039 
2040  /* TODO probably we just evaluated all expressions when checking the sol before it was added
2041  * would be nice to recognize this and skip reevaluating
2042  */
2043  soltag = SCIPgetExprNewSoltag(scip);
2044 
2045  SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
2046 
2047  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2050 
2051  for( c = 0; c < nconss; ++c )
2052  {
2053  /* skip constraints that are not enabled or deleted or have separation disabled */
2054  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2055  continue;
2056  assert(SCIPconsIsActive(conss[c]));
2057 
2058  consdata = SCIPconsGetData(conss[c]);
2059  assert(consdata != NULL);
2060 
2061  /* TODO we could remember for which constraints there is a chance that we would add anything,
2062  * i.e., there is some convex-like expression, and skip other constraints
2063  */
2064 
2065  ENFOLOG(
2066  {
2067  int i;
2068  SCIPinfoMessage(scip, enfologfile, " constraint ");
2069  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2070  SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2071  for( i = 0; i < consdata->nvarexprs; ++i )
2072  {
2073  SCIP_VAR* var;
2074  var = SCIPgetVarExprVar(consdata->varexprs[i]);
2075  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2076  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2077  }
2078  })
2079 
2080  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2081  assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2082 
2083  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2084  {
2085  SCIP_EXPR_OWNERDATA* ownerdata;
2086 
2087  ownerdata = SCIPexprGetOwnerData(expr);
2088  assert(ownerdata != NULL);
2089 
2090  /* we can only generate a cut from an estimator if there is an auxvar */
2091  if( ownerdata->auxvar == NULL )
2092  continue;
2093 
2094  /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2095  assert(SCIPexprGetEvalTag(expr) == soltag);
2096  assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2097  SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2098 
2099  /* generate cuts from estimators of each nonlinear handler that provides estimates */
2100  for( e = 0; e < ownerdata->nenfos; ++e )
2101  {
2102  SCIP_NLHDLR* nlhdlr;
2103 
2104  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2105  assert(nlhdlr != NULL);
2106 
2107  /* skip nlhdlr that does not implement estimate (so it does enfo) */
2108  if( !SCIPnlhdlrHasEstimate(nlhdlr) )
2109  continue;
2110 
2111  /* skip nlhdlr that does not participate in separation or looks like it would give only locally-valid estimators
2112  * (because it uses activities on vars/auxvars)
2113  */
2114  if( ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 || ownerdata->enfos[e]->sepaaboveusesactivity) &&
2115  ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 || ownerdata->enfos[e]->sepabelowusesactivity) )
2116  continue;
2117 
2118  /* skip nlhdlr_default on sum, as the estimator doesn't depend on the reference point (expr is linear in auxvars) */
2119  if( SCIPisExprSum(scip, expr) && strcmp(SCIPnlhdlrGetName(nlhdlr), "default") == 0 )
2120  continue;
2121 
2122  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables, since some nlhdlr expect this before their estimate is called */
2123  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
2124  ENFOLOG(
2125  SCIPinfoMessage(scip, enfologfile, " expr ");
2126  SCIPprintExpr(scip, expr, enfologfile);
2127  SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g, nlhdlr <%s> auxvalue: %.15g\n",
2128  (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar), SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
2129  )
2130  /* due to setting values of auxvars to expr values in sol, the auxvalue should equal to expr evalvalue */
2131  assert(SCIPisEQ(scip, ownerdata->enfos[e]->auxvalue, SCIPexprGetEvalValue(expr)));
2132 
2133  /* if nlhdlr wants to be called for overestimate and does not use local bounds, then call estimate of nlhdlr */
2134  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) && !ownerdata->enfos[e]->sepaaboveusesactivity )
2135  {
2136  SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, TRUE, rowpreps) );
2137  }
2138 
2139  /* if nlhdlr wants to be called for underestimate and does not use local bounds, then call estimate of nlhdlr */
2140  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) && !ownerdata->enfos[e]->sepabelowusesactivity )
2141  {
2142  SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, FALSE, rowpreps) );
2143  }
2144  }
2145  }
2146  }
2147 
2148  SCIPfreeExpriter(&it);
2149  SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
2150 
2151  return SCIP_OKAY;
2152 }
2153 
2154 /** processes the event that a new primal solution has been found */
2155 static
2156 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2158  SCIP_CONSHDLR* conshdlr;
2159  SCIP_CONSHDLRDATA* conshdlrdata;
2160  SCIP_SOL* sol;
2161 
2162  assert(scip != NULL);
2163  assert(event != NULL);
2164  assert(eventdata != NULL);
2165  assert(eventhdlr != NULL);
2166  assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND);
2167 
2168  conshdlr = (SCIP_CONSHDLR*)eventdata;
2169 
2170  if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2171  return SCIP_OKAY;
2172 
2173  sol = SCIPeventGetSol(event);
2174  assert(sol != NULL);
2175 
2176  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2177  assert(conshdlrdata != NULL);
2178 
2179  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2180  * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2181  * from the tree, but postprocessed via proposeFeasibleSolution
2182  */
2183  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2184  return SCIP_OKAY;
2185 
2186  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2187 
2188  SCIP_CALL( addTightEstimatorCuts(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol) );
2189 
2190  return SCIP_OKAY;
2191 }
2192 
2193 /** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2194  *
2195  * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2196  * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2197  *
2198  * Nothing will happen if SCIP is not in presolve or solve.
2199  */
2200 static
2202  SCIP* scip, /**< SCIP data structure */
2203  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2204  SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2205  SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2206  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2207  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2208  )
2209 {
2210  SCIP_VAR* var;
2211  SCIP_Bool tightenedlb;
2212  SCIP_Bool tightenedub;
2213  SCIP_Bool force;
2214 
2215  assert(scip != NULL);
2216  assert(conshdlr != NULL);
2217  assert(expr != NULL);
2218  assert(cutoff != NULL);
2219 
2220  /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2221  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, bounds));
2222 
2223  *cutoff = FALSE;
2224 
2225  /* do not tighten variable in problem stage (important for unittests)
2226  * TODO put some kind of #ifdef UNITTEST around this
2227  */
2229  return SCIP_OKAY;
2230 
2231  var = SCIPgetExprAuxVarNonlinear(expr);
2232  if( var == NULL )
2233  return SCIP_OKAY;
2234 
2235  /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2236  force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2237 
2238  /* try to tighten lower bound of (auxiliary) variable */
2239  SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2240  if( tightenedlb )
2241  {
2242  if( ntightenings != NULL )
2243  ++*ntightenings;
2244  SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2245  }
2246  if( *cutoff )
2247  {
2248  SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2249  return SCIP_OKAY;
2250  }
2251 
2252  /* try to tighten upper bound of (auxiliary) variable */
2253  SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2254  if( tightenedub )
2255  {
2256  if( ntightenings != NULL )
2257  ++*ntightenings;
2258  SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2259  }
2260  if( *cutoff )
2261  {
2262  SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2263  return SCIP_OKAY;
2264  }
2265 
2266  /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2267  * that seems unnecessary and we could easily undo this here, e.g.,
2268  * if( tightenedlb ) expr->activity.inf = bounds.inf
2269  */
2270 
2271  return SCIP_OKAY;
2272 }
2273 
2274 /** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2275  * and tries to tighten the bounds of the auxiliary variables accordingly
2276  */
2277 static
2279  SCIP* scip, /**< SCIP data structure */
2280  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2281  SCIP_EXPR* rootexpr, /**< expression */
2282  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2283  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2284  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2285  )
2286 {
2287  SCIP_EXPRITER* it;
2288  SCIP_EXPR* expr;
2289  SCIP_EXPR_OWNERDATA* ownerdata;
2290  SCIP_CONSHDLRDATA* conshdlrdata;
2291 
2292  assert(scip != NULL);
2293  assert(rootexpr != NULL);
2294 
2295  if( infeasible != NULL )
2296  *infeasible = FALSE;
2297  if( ntightenings != NULL )
2298  *ntightenings = 0;
2299 
2300  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2301  assert(conshdlrdata != NULL);
2302 
2303  /* if value is valid and empty, then we cannot improve, so do nothing */
2304  if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2305  {
2306  SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2307 
2308  if( infeasible != NULL )
2309  *infeasible = TRUE;
2310 
2311  /* just update tag to curboundstag */
2312  SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2313 
2314  return SCIP_OKAY;
2315  }
2316 
2317  /* if value is up-to-date, then nothing to do */
2318  if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2319  {
2320  SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2321 
2322  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2323 
2324  return SCIP_OKAY;
2325  }
2326 
2327  ownerdata = SCIPexprGetOwnerData(rootexpr);
2328  assert(ownerdata != NULL);
2329 
2330  /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2331  * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2332  * during detect, we are in some in-between state where we may want to eval activity
2333  * on exprs that we did not notify about their activity usage
2334  */
2335  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2336  {
2337 #ifdef DEBUG_PROP
2338  SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2339 #endif
2340  SCIPABORT();
2341  return SCIP_OKAY;
2342  }
2343 
2344  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2345  SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2347 
2348  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2349  {
2350  switch( SCIPexpriterGetStageDFS(it) )
2351  {
2353  {
2354  /* skip child if it has been evaluated already */
2355  SCIP_EXPR* child;
2356 
2357  child = SCIPexpriterGetChildExprDFS(it);
2358  if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2359  {
2360  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2361  *infeasible = TRUE;
2362 
2363  expr = SCIPexpriterSkipDFS(it);
2364  continue;
2365  }
2366 
2367  break;
2368  }
2369 
2371  {
2372  SCIP_INTERVAL activity;
2373 
2374  /* we should not have entered this expression if its activity was already up to date */
2375  assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2376 
2377  ownerdata = SCIPexprGetOwnerData(expr);
2378  assert(ownerdata != NULL);
2379 
2380  /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2381  * so we can assume that the activity is up to date for all these variables
2382  * UNLESS we changed the method used to evaluate activity of variable expressions
2383  * or we currently use global bounds (varevents are catched for local bound changes only)
2384  */
2385  if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2386  SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2387  {
2388 #ifndef NDEBUG
2389  SCIP_INTERVAL exprhdlrinterval;
2390 
2391  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2392  assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2393  assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2394 #endif
2395 #ifdef DEBUG_PROP
2396  SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2397 #endif
2398  SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2399 
2400  break;
2401  }
2402 
2403  if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2404  {
2405  /* start with entire activity if current one is invalid */
2407  }
2409  {
2410  /* If already empty, then don't try to compute even better activity.
2411  * If cons_nonlinear were alone, then we should have noted that we are infeasible
2412  * so an assert(infeasible == NULL || *infeasible) should work here.
2413  * However, after reporting a cutoff due to expr->activity being empty,
2414  * SCIP may wander to a different node and call propagation again.
2415  * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2416  * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2417  * we will still have expr->activity being empty, but will have forgotten
2418  * that we found infeasibility here before (!2221#note_134120).
2419  * Therefore we just set *infeasibility=TRUE here and stop.
2420  */
2421  if( infeasible != NULL )
2422  *infeasible = TRUE;
2423  SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2424  break;
2425  }
2426  else
2427  {
2428  /* start with current activity, since it is valid */
2429  activity = SCIPexprGetActivity(expr);
2430  }
2431 
2432  /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2433  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2434  {
2435 #ifdef DEBUG_PROP
2436  SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2437 #endif
2438  break;
2439  }
2440 
2441 #ifdef DEBUG_PROP
2442  SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2443  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2444  SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2445 #endif
2446 
2447  /* run interval eval of nonlinear handlers or expression handler */
2448  if( ownerdata->nenfos > 0 )
2449  {
2450  SCIP_NLHDLR* nlhdlr;
2451  SCIP_INTERVAL nlhdlrinterval;
2452  int e;
2453 
2454  /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2455  for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2456  {
2457  /* skip nlhdlr if it does not want to participate in activity computation */
2458  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2459  continue;
2460 
2461  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2462  assert(nlhdlr != NULL);
2463 
2464  /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2465  if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2466  continue;
2467 
2468  /* let nlhdlr evaluate current expression */
2469  nlhdlrinterval = activity;
2470  SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2471  &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2472 #ifdef DEBUG_PROP
2473  SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2474 #endif
2475 
2476  /* update activity by intersecting with computed activity */
2477  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2478 #ifdef DEBUG_PROP
2479  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2480 #endif
2481  }
2482  }
2483  else
2484  {
2485  /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2486  SCIP_INTERVAL exprhdlrinterval = activity;
2487  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2488 #ifdef DEBUG_PROP
2489  SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2490 #endif
2491 
2492  /* update expr->activity by intersecting with computed activity */
2493  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2494 #ifdef DEBUG_PROP
2495  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2496 #endif
2497  }
2498 
2499  /* if expression is integral, then we try to tighten the interval bounds a bit
2500  * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2501  * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2502  * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2503  * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2504  * (constants should be ok, too)
2505  */
2506  if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2507  {
2508  if( activity.inf > -SCIP_INTERVAL_INFINITY )
2509  activity.inf = SCIPceil(scip, activity.inf);
2510  if( activity.sup < SCIP_INTERVAL_INFINITY )
2511  activity.sup = SCIPfloor(scip, activity.sup);
2512 #ifdef DEBUG_PROP
2513  SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2514 #endif
2515  }
2516 
2517  /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2518  * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2519  */
2520  if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2521  {
2522  SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2523  SCIPintervalSetEmpty(&activity);
2524  }
2525 
2526  /* now finally store activity in expr */
2527  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2528 
2530  {
2531  if( infeasible != NULL )
2532  *infeasible = TRUE;
2533  }
2534  else if( tightenauxvars && ownerdata->auxvar != NULL )
2535  {
2536  SCIP_Bool tighteninfeasible;
2537 
2538  SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2539  if( tighteninfeasible )
2540  {
2541  if( infeasible != NULL )
2542  *infeasible = TRUE;
2543  SCIPintervalSetEmpty(&activity);
2544  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2545  }
2546  }
2547 
2548  break;
2549  }
2550 
2551  default:
2552  /* you should never be here */
2553  SCIPerrorMessage("unexpected iterator stage\n");
2554  SCIPABORT();
2555  break;
2556  }
2557 
2558  expr = SCIPexpriterGetNext(it);
2559  }
2560 
2561  SCIPfreeExpriter(&it);
2562 
2563  return SCIP_OKAY;
2564 }
2565 
2566 /** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2567  *
2568  * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2569  *
2570  * If `subsetsufficient` is FALSE, then we require
2571  * - a change from an unbounded interval to a bounded one, or
2572  * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2573  * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2574  */
2575 static
2577  SCIP* scip, /**< SCIP data structure */
2578  SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2579  SCIP_INTERVAL newinterval, /**< new interval */
2580  SCIP_INTERVAL oldinterval /**< old interval */
2581  )
2582 {
2583  assert(scip != NULL);
2584  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2585  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2586 
2587  if( subsetsufficient )
2588  /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2589  return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2590 
2591  /* check whether lower bound of interval becomes finite */
2592  if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2593  return TRUE;
2594 
2595  /* check whether upper bound of interval becomes finite */
2596  if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2597  return TRUE;
2598 
2599  /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2600  if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2601  return TRUE;
2602 
2603  /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2604  if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2605  return TRUE;
2606 
2607  /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2608  if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2609  return TRUE;
2610 
2611  return FALSE;
2612 }
2613 
2614 /** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2615  *
2616  * The expression will be traversed in breadth first search by using this queue.
2617  *
2618  * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2619  * forwardPropExpr() before calling this function.
2620  *
2621  * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2622  */
2623 static
2625  SCIP* scip, /**< SCIP data structure */
2626  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2627  SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2628  int* ntightenings /**< buffer to store the number of (variable) tightenings */
2629  )
2630 {
2631  SCIP_CONSHDLRDATA* conshdlrdata;
2632  SCIP_EXPR* expr;
2633  SCIP_EXPR_OWNERDATA* ownerdata;
2634 
2635  assert(infeasible != NULL);
2636  assert(ntightenings != NULL);
2637 
2638  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2639  assert(conshdlrdata != NULL);
2640 
2641  *ntightenings = 0;
2642 
2643  /* main loop that calls reverse propagation for expressions on the queue
2644  * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2645  */
2646  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2647  {
2648  SCIP_INTERVAL propbounds;
2649  int e;
2650 
2651  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2652  assert(expr != NULL);
2653 
2654  ownerdata = SCIPexprGetOwnerData(expr);
2655  assert(ownerdata != NULL);
2656 
2657  assert(ownerdata->inpropqueue);
2658  /* mark that the expression is not in the queue anymore */
2659  ownerdata->inpropqueue = FALSE;
2660 
2661  /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2662  * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2663  */
2664  assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2665  assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2666  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2667 
2668  /* this intersects propbounds with activity and auxvar bounds
2669  * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2670  * auxvar bounds separately, so disabling this for now
2671  */
2672 #ifdef SCIP_DISABLED_CODE
2673  propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2674  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, propbounds) )
2675  {
2676  *infeasible = TRUE;
2677  break;
2678  }
2679 #else
2680  propbounds = ownerdata->propbounds;
2681 #endif
2682 
2683  if( ownerdata->nenfos > 0 )
2684  {
2685  /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2686  for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2687  {
2688  SCIP_NLHDLR* nlhdlr;
2689  int nreds;
2690 
2691  /* skip nlhdlr if it does not want to participate in activity computation */
2692  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2693  continue;
2694 
2695  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2696  assert(nlhdlr != NULL);
2697 
2698  /* call the reverseprop of the nlhdlr */
2699 #ifdef SCIP_DEBUG
2700  SCIPdebugMsg(scip, "call reverse propagation for ");
2701  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2702  SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2703 #endif
2704 
2705  nreds = 0;
2706  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2707  assert(nreds >= 0);
2708  *ntightenings += nreds;
2709  }
2710  }
2712  {
2713  /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2714  SCIP_INTERVAL* childrenbounds;
2715  int c;
2716 
2717 #ifdef SCIP_DEBUG
2718  SCIPdebugMsg(scip, "call reverse propagation for ");
2719  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2720  SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2721 #endif
2722 
2723  /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2724  * been initialized in detectNlhdlr yet (nenfos < 0)
2725  */
2726  assert(ownerdata->nenfos < 0);
2727 
2728  SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2729  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2730  childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2731 
2732  /* call the reverseprop of the exprhdlr */
2733  SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2734 
2735  if( !*infeasible )
2736  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2737  {
2738  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2739  }
2740 
2741  SCIPfreeBufferArray(scip, &childrenbounds);
2742  }
2743  }
2744 
2745  /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2746  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2747  {
2748  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2749  assert(expr != NULL);
2750 
2751  ownerdata = SCIPexprGetOwnerData(expr);
2752  assert(ownerdata != NULL);
2753 
2754  /* mark that the expression is not in the queue anymore */
2755  ownerdata->inpropqueue = FALSE;
2756  }
2757 
2758  return SCIP_OKAY;
2759 }
2760 
2761 /** calls domain propagation for a given set of constraints
2762  *
2763  * The algorithm alternates calls of forward and reverse propagation.
2764  * Forward propagation ensures that activity of expressions is up to date.
2765  * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2766  * [lhs,rhs] interval as starting point.
2767  *
2768  * The propagation algorithm works as follows:
2769  * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2770  * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2771  * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2772  * provide tighter bounds
2773  * 3. apply reverse propagation to all collected expressions; don't explore
2774  * sub-expressions which have not changed since the beginning of the propagation loop
2775  * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2776  *
2777  * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2778  * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2779  * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2780  *
2781  * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2782  * e.g., try less to propagate on convex constraints?
2783  */
2784 static
2786  SCIP* scip, /**< SCIP data structure */
2787  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2788  SCIP_CONS** conss, /**< constraints to propagate */
2789  int nconss, /**< total number of constraints */
2790  SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2791  SCIP_RESULT* result, /**< pointer to store the result */
2792  int* nchgbds /**< buffer to add the number of changed bounds */
2793  )
2794 {
2795  SCIP_CONSHDLRDATA* conshdlrdata;
2796  SCIP_CONSDATA* consdata;
2797  SCIP_EXPR_OWNERDATA* ownerdata;
2798  SCIP_Bool cutoff = FALSE;
2799  SCIP_INTERVAL conssides;
2800  int ntightenings;
2801  int roundnr;
2802  SCIP_EXPRITER* revpropcollectit = NULL;
2803  int i;
2804 
2805  assert(scip != NULL);
2806  assert(conshdlr != NULL);
2807  assert(conss != NULL);
2808  assert(nconss >= 0);
2809  assert(result != NULL);
2810  assert(nchgbds != NULL);
2811  assert(*nchgbds >= 0);
2812 
2813  /* no constraints to propagate */
2814  if( nconss == 0 )
2815  {
2816  *result = SCIP_DIDNOTRUN;
2817  return SCIP_OKAY;
2818  }
2819 
2820  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2821  assert(conshdlrdata != NULL);
2822  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2823  assert(!conshdlrdata->globalbounds);
2824 
2825  *result = SCIP_DIDNOTFIND;
2826  roundnr = 0;
2827 
2828  /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2829  conshdlrdata->forceboundtightening = force;
2830 
2831  /* invalidate all propbounds (probably not needed) */
2832  ++conshdlrdata->curpropboundstag;
2833 
2834  /* create iterator that we will use if we need to look at all auxvars */
2835  if( conshdlrdata->propauxvars )
2836  {
2837  SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2838  }
2839 
2840  /* main propagation loop */
2841  do
2842  {
2843  SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2844 
2845  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2846 
2847  /* apply forward propagation (update expression activities)
2848  * and add promising root expressions into queue for reversepropagation
2849  */
2850  for( i = 0; i < nconss; ++i )
2851  {
2852  consdata = SCIPconsGetData(conss[i]);
2853  assert(consdata != NULL);
2854 
2855  /* skip deleted, non-active, or propagation-disabled constraints */
2856  if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2857  continue;
2858 
2859  /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2860  * activity didn't change
2861  */
2862  if( consdata->ispropagated )
2863  continue;
2864 
2865  /* update activities in expression */
2866  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2867  SCIPdebugPrintCons(scip, conss[i], NULL);
2868 
2869  ntightenings = 0;
2870  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2871  assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2872 
2873  if( cutoff )
2874  {
2875  SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2876  *result = SCIP_CUTOFF;
2877  break;
2878  }
2879 
2880  ownerdata = SCIPexprGetOwnerData(consdata->expr);
2881 
2882  /* TODO for a constraint that only has an auxvar for consdata->expr (e.g., convex quadratic), we could also just do the if(TRUE)-branch */
2883  if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2884  {
2885  /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2886  * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2887  * so taking auxvar bounds is enough)
2888  */
2889  if( ownerdata->auxvar == NULL )
2890  {
2891  /* relax sides by SCIPepsilon() and handle infinite sides */
2892  SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2893  SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2894  SCIPintervalSetBounds(&conssides, lhs, rhs);
2895  }
2896  else
2897  {
2898  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2899  }
2900  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2901  }
2902  else
2903  {
2904  /* check whether bounds of any auxvar used in constraint provides a tightening
2905  * (for the root expression, bounds of auxvar are initially set to constraint sides)
2906  * but skip exprs that have an auxvar, but do not participate in propagation
2907  */
2908  SCIP_EXPR* expr;
2909 
2910  assert(revpropcollectit != NULL);
2911  SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2912  for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2913  {
2914  ownerdata = SCIPexprGetOwnerData(expr);
2915  assert(ownerdata != NULL);
2916 
2917  if( ownerdata->auxvar == NULL )
2918  continue;
2919 
2920  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2921  continue;
2922 
2923  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2924  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2925  }
2926  }
2927 
2928  if( cutoff )
2929  {
2930  SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2931  *result = SCIP_CUTOFF;
2932  break;
2933  }
2934 
2935  assert(ntightenings >= 0);
2936  if( ntightenings > 0 )
2937  {
2938  *nchgbds += ntightenings;
2939  *result = SCIP_REDUCEDDOM;
2940  }
2941 
2942  /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2943  consdata->ispropagated = TRUE;
2944  }
2945 
2946  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2947  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2948  assert(ntightenings >= 0);
2949  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2950 
2951  if( cutoff )
2952  {
2953  SCIPdebugMsg(scip, " -> cutoff\n");
2954  *result = SCIP_CUTOFF;
2955  break;
2956  }
2957 
2958  if( ntightenings > 0 )
2959  {
2960  *nchgbds += ntightenings;
2961  *result = SCIP_REDUCEDDOM;
2962  }
2963  }
2964  while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2965 
2966  if( conshdlrdata->propauxvars )
2967  {
2968  SCIPfreeExpriter(&revpropcollectit);
2969  }
2970 
2971  conshdlrdata->forceboundtightening = FALSE;
2972 
2973  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2974  ++conshdlrdata->curpropboundstag;
2975 
2976  return SCIP_OKAY;
2977 }
2978 
2979 /** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2980  *
2981  * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2982  *
2983  * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2984  * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2985  */
2986 static
2988  SCIP* scip, /**< SCIP data structure */
2989  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2990  SCIP_CONS** conss, /**< constraints to propagate */
2991  int nconss, /**< total number of constraints */
2992  SCIP_RESULT* result, /**< pointer to store the result */
2993  int* nchgbds /**< buffer to add the number of changed bounds */
2994  )
2995 {
2996  SCIP_CONSDATA* consdata;
2997  SCIP_EXPRITER* it;
2998  SCIP_EXPR* expr;
2999  SCIP_EXPR_OWNERDATA* ownerdata;
3000  SCIP_Bool cutoff = FALSE;
3001  int ntightenings;
3002  int c;
3003  int e;
3004 
3005  assert(scip != NULL);
3006  assert(conshdlr != NULL);
3007  assert(conss != NULL);
3008  assert(nconss >= 0);
3009  assert(result != NULL);
3010  assert(nchgbds != NULL);
3011  assert(*nchgbds >= 0);
3012 
3013  assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
3014  assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
3015  assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
3016 
3017  *result = SCIP_DIDNOTFIND;
3018 
3019  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3021 
3022  for( c = 0; c < nconss && !cutoff; ++c )
3023  {
3024  /* skip deleted, non-active, or propagation-disabled constraints */
3025  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
3026  continue;
3027 
3028  consdata = SCIPconsGetData(conss[c]);
3029  assert(consdata != NULL);
3030 
3031  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
3032  {
3033  ownerdata = SCIPexprGetOwnerData(expr);
3034  assert(ownerdata != NULL);
3035 
3036  /* call reverseprop for those nlhdlr that participate in this expr's activity computation
3037  * this will propagate the current activity
3038  */
3039  for( e = 0; e < ownerdata->nenfos; ++e )
3040  {
3041  SCIP_NLHDLR* nlhdlr;
3042  assert(ownerdata->enfos[e] != NULL);
3043 
3044  nlhdlr = ownerdata->enfos[e]->nlhdlr;
3045  assert(nlhdlr != NULL);
3046  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
3047  continue;
3048 
3049  SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
3050  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
3051  ntightenings = 0;
3052  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
3053  SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
3054 
3055  if( cutoff )
3056  {
3057  /* stop everything if we detected infeasibility */
3058  SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3059  *result = SCIP_CUTOFF;
3060  break;
3061  }
3062 
3063  assert(ntightenings >= 0);
3064  if( ntightenings > 0 )
3065  {
3066  *nchgbds += ntightenings;
3067  *result = SCIP_REDUCEDDOM;
3068  }
3069  }
3070  }
3071  }
3072 
3073  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
3074  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
3075  assert(ntightenings >= 0);
3076 
3077  if( cutoff )
3078  {
3079  SCIPdebugMsg(scip, " -> cutoff\n");
3080  *result = SCIP_CUTOFF;
3081  }
3082  else if( ntightenings > 0 )
3083  {
3084  *nchgbds += ntightenings;
3085  *result = SCIP_REDUCEDDOM;
3086  }
3087 
3088  SCIPfreeExpriter(&it);
3089 
3090  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
3091  ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
3092 
3093  return SCIP_OKAY;
3094 }
3095 
3096 /** propagates variable locks through expression and adds locks to variables */
3097 static
3099  SCIP* scip, /**< SCIP data structure */
3100  SCIP_EXPR* expr, /**< expression */
3101  int nlockspos, /**< number of positive locks */
3102  int nlocksneg /**< number of negative locks */
3103  )
3104 {
3105  SCIP_EXPR_OWNERDATA* ownerdata;
3106  SCIP_EXPRITER* it;
3107  SCIP_EXPRITER_USERDATA ituserdata;
3108 
3109  assert(expr != NULL);
3110 
3111  /* if no locks, then nothing to propagate */
3112  if( nlockspos == 0 && nlocksneg == 0 )
3113  return SCIP_OKAY;
3114 
3115  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3118  assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3119 
3120  /* store locks in root node */
3121  ituserdata.intvals[0] = nlockspos;
3122  ituserdata.intvals[1] = nlocksneg;
3123  SCIPexpriterSetCurrentUserData(it, ituserdata);
3124 
3125  while( !SCIPexpriterIsEnd(it) )
3126  {
3127  /* collect locks */
3128  ituserdata = SCIPexpriterGetCurrentUserData(it);
3129  nlockspos = ituserdata.intvals[0];
3130  nlocksneg = ituserdata.intvals[1];
3131 
3132  ownerdata = SCIPexprGetOwnerData(expr);
3133 
3134  switch( SCIPexpriterGetStageDFS(it) )
3135  {
3137  {
3138  if( SCIPisExprVar(scip, expr) )
3139  {
3140  /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3141  SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3142  }
3143 
3144  /* add locks to expression */
3145  ownerdata->nlockspos += nlockspos;
3146  ownerdata->nlocksneg += nlocksneg;
3147 
3148  /* add monotonicity information if expression has been locked for the first time */
3149  if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3151  {
3152  int i;
3153 
3154  assert(ownerdata->monotonicity == NULL);
3155  assert(ownerdata->monotonicitysize == 0);
3156 
3157  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3158  ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3159 
3160  /* store the monotonicity for each child */
3161  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3162  {
3163  SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3164  }
3165  }
3166  break;
3167  }
3168 
3170  {
3171  /* remove monotonicity information if expression has been unlocked */
3172  if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3173  {
3174  assert(ownerdata->monotonicitysize > 0);
3175  /* keep this assert for checking whether someone changed an expression without updating locks properly */
3176  assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3177 
3178  SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3179  ownerdata->monotonicitysize = 0;
3180  }
3181  break;
3182  }
3183 
3185  {
3186  SCIP_MONOTONE monotonicity;
3187 
3188  /* get monotonicity of child */
3189  /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3190  * SCIPcallExprMonotonicity
3191  */
3192  monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3193 
3194  /* compute resulting locks of the child expression */
3195  switch( monotonicity )
3196  {
3197  case SCIP_MONOTONE_INC:
3198  ituserdata.intvals[0] = nlockspos;
3199  ituserdata.intvals[1] = nlocksneg;
3200  break;
3201  case SCIP_MONOTONE_DEC:
3202  ituserdata.intvals[0] = nlocksneg;
3203  ituserdata.intvals[1] = nlockspos;
3204  break;
3205  case SCIP_MONOTONE_UNKNOWN:
3206  ituserdata.intvals[0] = nlockspos + nlocksneg;
3207  ituserdata.intvals[1] = nlockspos + nlocksneg;
3208  break;
3209  case SCIP_MONOTONE_CONST:
3210  ituserdata.intvals[0] = 0;
3211  ituserdata.intvals[1] = 0;
3212  break;
3213  }
3214  /* set locks in child expression */
3215  SCIPexpriterSetChildUserData(it, ituserdata);
3216 
3217  break;
3218  }
3219 
3220  default :
3221  /* you should never be here */
3222  SCIPABORT();
3223  break;
3224  }
3225 
3226  expr = SCIPexpriterGetNext(it);
3227  }
3228 
3229  SCIPfreeExpriter(&it);
3230 
3231  return SCIP_OKAY;
3232 }
3233 
3234 /** main function for adding locks to expressions and variables
3235  *
3236  * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3237  * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3238  * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3239  * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3240  * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3241  * the computed monotonicity information of each expression until all locks of an expression have been removed,
3242  * which implies that updating the monotonicity information during the next locking of this expression does not
3243  * break existing locks.
3244  *
3245  * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3246  * locks from an expression and repropagating them after the structural changes have been applied.
3247  * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3248  * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3249  */
3250 static
3252  SCIP* scip, /**< SCIP data structure */
3253  SCIP_CONS* cons, /**< nonlinear constraint */
3254  int nlockspos, /**< number of positive rounding locks */
3255  int nlocksneg /**< number of negative rounding locks */
3256  )
3257 {
3258  SCIP_CONSDATA* consdata;
3259 
3260  assert(cons != NULL);
3261 
3262  if( nlockspos == 0 && nlocksneg == 0 )
3263  return SCIP_OKAY;
3264 
3265  consdata = SCIPconsGetData(cons);
3266  assert(consdata != NULL);
3267 
3268  /* no constraint sides -> nothing to lock */
3269  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3270  return SCIP_OKAY;
3271 
3272  /* remember locks */
3273  consdata->nlockspos += nlockspos;
3274  consdata->nlocksneg += nlocksneg;
3275 
3276  assert(consdata->nlockspos >= 0);
3277  assert(consdata->nlocksneg >= 0);
3278 
3279  /* compute locks for lock propagation */
3280  if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3281  {
3282  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3283  }
3284  else if( !SCIPisInfinity(scip, consdata->rhs) )
3285  {
3286  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3287  }
3288  else
3289  {
3290  assert(!SCIPisInfinity(scip, -consdata->lhs));
3291  SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3292  }
3293 
3294  return SCIP_OKAY;
3295 }
3296 
3297 /** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3298 static
3300  SCIP* scip, /**< SCIP data structure */
3301  SCIP_CONS* cons /**< nonlinear constraint */
3302  )
3303 {
3304  SCIP_CONSDATA* consdata;
3305 
3306  assert(scip != NULL);
3307  assert(cons != NULL);
3308 
3309  consdata = SCIPconsGetData(cons);
3310  assert(consdata != NULL);
3311  assert(consdata->expr != NULL);
3312 
3313  if( consdata->nlrow != NULL )
3314  {
3315  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3316  }
3317 
3318  /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3319  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3320  0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3321 
3322  if( SCIPisExprSum(scip, consdata->expr) )
3323  {
3324  /* if root is a sum, then split into linear and nonlinear terms */
3325  SCIP_EXPR* nonlinpart;
3326  SCIP_EXPR* child;
3327  SCIP_Real* coefs;
3328  int i;
3329 
3330  coefs = SCIPgetCoefsExprSum(consdata->expr);
3331 
3332  /* constant term of sum */
3333  SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3334 
3335  /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3336  SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3337 
3338  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3339  {
3340  child = SCIPexprGetChildren(consdata->expr)[i];
3341  if( SCIPisExprVar(scip, child) )
3342  {
3343  /* linear term */
3344  SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3345  }
3346  else
3347  {
3348  /* nonlinear term */
3349  SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3350  }
3351  }
3352 
3353  if( SCIPexprGetNChildren(nonlinpart) > 0 )
3354  {
3355  /* add expression to nlrow (this will make a copy) */
3356  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3357  }
3358  SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3359  }
3360  else
3361  {
3362  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3363  }
3364 
3365  return SCIP_OKAY;
3366 }
3367 
3368 /** compares enfodata by enforcement priority of nonlinear handler
3369  *
3370  * If handlers have same enforcement priority, then compare by detection priority, then by name.
3371  */
3372 static
3373 SCIP_DECL_SORTPTRCOMP(enfodataCmp)
3375  SCIP_NLHDLR* h1;
3376  SCIP_NLHDLR* h2;
3377 
3378  assert(elem1 != NULL);
3379  assert(elem2 != NULL);
3380 
3381  h1 = ((EXPRENFO*)elem1)->nlhdlr;
3382  h2 = ((EXPRENFO*)elem2)->nlhdlr;
3383 
3384  assert(h1 != NULL);
3385  assert(h2 != NULL);
3386 
3389 
3392 
3393  return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3394 }
3395 
3396 /** install nlhdlrs in one expression */
3397 static
3399  SCIP* scip, /**< SCIP data structure */
3400  SCIP_EXPR* expr, /**< expression for which to run detection routines */
3401  SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3402  )
3403 {
3404  SCIP_EXPR_OWNERDATA* ownerdata;
3405  SCIP_CONSHDLRDATA* conshdlrdata;
3406  SCIP_NLHDLR_METHOD enforcemethodsallowed;
3407  SCIP_NLHDLR_METHOD enforcemethods;
3408  SCIP_NLHDLR_METHOD enforcemethodsnew;
3409  SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3410  SCIP_NLHDLR_METHOD nlhdlrparticipating;
3411  SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3412  int enfossize; /* allocated length of expr->enfos array */
3413  int h;
3414 
3415  assert(expr != NULL);
3416 
3417  ownerdata = SCIPexprGetOwnerData(expr);
3418  assert(ownerdata != NULL);
3419 
3420  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3421  assert(conshdlrdata != NULL);
3422  assert(conshdlrdata->auxvarid >= 0);
3423  assert(!conshdlrdata->indetect);
3424 
3425  /* there should be no enforcer yet and detection should not even have considered expr yet */
3426  assert(ownerdata->nenfos < 0);
3427  assert(ownerdata->enfos == NULL);
3428 
3429  /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3430  * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3431  * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3432  * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3433  * - if no one uses activity, then do not need activity methods
3434  */
3435  enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3436  if( ownerdata->nauxvaruses == 0 )
3437  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3438  else
3439  {
3440  if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3441  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3442  if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3443  enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3444  }
3445  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3446  enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3447 
3448  /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3449  assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3450 
3451  /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3452  enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3453 
3454  ownerdata->nenfos = 0;
3455  enfossize = 2;
3456  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3457  conshdlrdata->indetect = TRUE;
3458 
3459  SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3460  cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3461  (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3462  (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3463  (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3464 
3465  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3466  {
3467  SCIP_NLHDLR* nlhdlr;
3468 
3469  nlhdlr = conshdlrdata->nlhdlrs[h];
3470  assert(nlhdlr != NULL);
3471 
3472  /* skip disabled nlhdlrs */
3473  if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3474  continue;
3475 
3476  /* call detect routine of nlhdlr */
3477  nlhdlrexprdata = NULL;
3478  enforcemethodsnew = enforcemethods;
3479  nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3480  conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3481  conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3482  SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3483 
3484  /* nlhdlr might have claimed more than needed: clean up sepa flags */
3485  nlhdlrparticipating &= enforcemethodsallowed;
3486 
3487  /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3488  assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3489 
3490  /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3491  * They are also cleaned up here to ensure that only the needed methods are claimed.
3492  */
3493  nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3494 
3495  /* nlhdlr needs to participate for the methods it is enforcing */
3496  assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3497 
3498  if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3499  {
3500  /* nlhdlr might not have detected anything, or all set flags might have been removed by
3501  * clean up; in the latter case, we may need to free nlhdlrexprdata */
3502 
3503  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3504  if( nlhdlrexprdata != NULL )
3505  {
3506  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3507  }
3508  /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3509  assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3510 
3511  SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3512 
3513  continue;
3514  }
3515 
3516  SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3517  SCIPnlhdlrGetName(nlhdlr),
3518  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3519  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3520  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3521 
3522  /* store nlhdlr and its data */
3523  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3524  SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3525  ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3526  ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3527  ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3528  ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3529  ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3530  ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3531  ownerdata->nenfos++;
3532 
3533  /* update enforcement flags */
3534  enforcemethods = enforcemethodsnew;
3535  }
3536 
3537  conshdlrdata->indetect = FALSE;
3538 
3539  /* stop if an enforcement method is missing but we are already in solving stage
3540  * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3541  */
3542  if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3543  {
3544  SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3545  return SCIP_ERROR;
3546  }
3547 
3548  assert(ownerdata->nenfos > 0);
3549 
3550  /* sort nonlinear handlers by enforcement priority, in decreasing order */
3551  if( ownerdata->nenfos > 1 )
3552  SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3553 
3554  /* resize enfos array to be nenfos long */
3555  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3556 
3557  return SCIP_OKAY;
3558 }
3559 
3560 /** detect nlhdlrs that can handle the expressions */
3561 static
3563  SCIP* scip, /**< SCIP data structure */
3564  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3565  SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3566  int nconss /**< total number of constraints */
3567  )
3568 {
3569  SCIP_CONSHDLRDATA* conshdlrdata;
3570  SCIP_CONSDATA* consdata;
3571  SCIP_EXPR* expr;
3572  SCIP_EXPR_OWNERDATA* ownerdata;
3573  SCIP_EXPRITER* it;
3574  int i;
3575 
3576  assert(conss != NULL || nconss == 0);
3577  assert(nconss >= 0);
3578  assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING || SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING); /* should only be called in presolve or initsolve or consactive */
3579 
3580  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3581  assert(conshdlrdata != NULL);
3582 
3583  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3585 
3586  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3587  {
3588  /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3589  * for example, this happens if globally valid nonlinear constraints are added during the tree search
3590  */
3592  conshdlrdata->globalbounds = TRUE;
3593  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3594  }
3595 
3596  for( i = 0; i < nconss; ++i )
3597  {
3598  assert(conss != NULL && conss[i] != NULL);
3599 
3600  consdata = SCIPconsGetData(conss[i]);
3601  assert(consdata != NULL);
3602  assert(consdata->expr != NULL);
3603 
3604  /* if a constraint is separated, we currently need it to be initial, too
3605  * this is because INITLP will create the auxiliary variables that are used for any separation
3606  * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3607  */
3608  assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3609 
3610  ownerdata = SCIPexprGetOwnerData(consdata->expr);
3611  assert(ownerdata != NULL);
3612 
3613  /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3614  * then we would normally skip to run DETECT again
3615  * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3616  * thus, if expr is the root expression, we rerun DETECT
3617  */
3618  if( ownerdata->nenfos > 0 )
3619  {
3620  SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3621  assert(ownerdata->nenfos < 0);
3622  }
3623 
3624  /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3625  * this way we can treat the root expression like any other expression when enforcing via separation
3626  * if constraint will be propagated, then register activity usage of root expression
3627  * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3628  */
3629  conshdlrdata->indetect = TRUE;
3630  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, consdata->expr,
3631  SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3632  SCIPconsIsPropagated(conss[i]),
3633  FALSE, FALSE) );
3634  conshdlrdata->indetect = FALSE;
3635 
3636  /* compute integrality information for all subexpressions */
3637  SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3638 
3639  /* run detectNlhdlr on all expr where required */
3640  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3641  {
3642  ownerdata = SCIPexprGetOwnerData(expr);
3643  assert(ownerdata != NULL);
3644 
3645  /* skip exprs that we already looked at */
3646  if( ownerdata->nenfos >= 0 )
3647  continue;
3648 
3649  /* if there is use of the auxvar, then someone requires that
3650  * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3651  * thus, we need to find nlhdlrs that separate or estimate
3652  * if there is use of the activity, then there is someone requiring that
3653  * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3654  * thus, we need to find nlhdlrs that do interval-evaluation
3655  */
3656  if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3657  {
3658  SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3659 
3660  assert(ownerdata->nenfos >= 0);
3661  }
3662  else
3663  {
3664  /* remember that we looked at this expression during detectNlhdlrs
3665  * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3666  * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3667  * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3668  */
3669  ownerdata->nenfos = 0;
3670  }
3671  }
3672 
3673  /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3674  if( SCIPconsIsPropagated(conss[i]) )
3675  consdata->ispropagated = FALSE;
3676  }
3677 
3678  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3679  {
3680  /* ensure that the local bounds are used again when reevaluating the expressions later;
3681  * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3682  */
3684  conshdlrdata->globalbounds = FALSE;
3685  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3686  }
3687  else
3688  {
3689  /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3691  }
3692 
3693  SCIPfreeExpriter(&it);
3694 
3695  return SCIP_OKAY;
3696 }
3697 
3698 /** initializes (pre)solving data of constraints
3699  *
3700  * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3701  * not be modified.
3702  * In particular, this function
3703  * - runs the detection method of nlhldrs
3704  * - looks for unlocked linear variables
3705  * - checks curvature (if not in presolve)
3706  * - creates and add row to NLP (if not in presolve)
3707  *
3708  * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3709  * e.g., it should be called in INITSOL and for constraints that are added during solve.
3710  */
3711 static
3713  SCIP* scip, /**< SCIP data structure */
3714  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3715  SCIP_CONS** conss, /**< constraints */
3716  int nconss /**< number of constraints */
3717  )
3718 {
3719  int c;
3720 
3721  for( c = 0; c < nconss; ++c )
3722  {
3723  /* check for a linear variable that can be increase or decreased without harming feasibility */
3724  findUnlockedLinearVar(scip, conss[c]);
3725 
3727  {
3728  SCIP_CONSDATA* consdata;
3729  SCIP_Bool success = FALSE;
3730 
3731  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3732  assert(consdata != NULL);
3733  assert(consdata->expr != NULL);
3734 
3735  if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3736  {
3737  /* call the curvature detection algorithm of the convex nonlinear handler
3738  * Check only for those curvature that may result in a convex inequality, i.e.,
3739  * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3740  * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3741  */
3742  if( !SCIPisInfinity(scip, -consdata->lhs) )
3743  {
3744  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3745  if( success )
3746  consdata->curv = SCIP_EXPRCURV_CONCAVE;
3747  }
3748  if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3749  {
3750  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3751  if( success )
3752  consdata->curv = SCIP_EXPRCURV_CONVEX;
3753  }
3754  }
3755  else
3756  {
3757  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3758  {
3759  SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3760  consdata->curv = SCIP_EXPRCURV_LINEAR;
3761  }
3762  else
3763  {
3764  consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3765  }
3766  }
3767  SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3768 
3769  /* add nlrow representation to NLP, if NLP had been constructed */
3770  if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3771  {
3772  if( consdata->nlrow == NULL )
3773  {
3774  SCIP_CALL( createNlRow(scip, conss[c]) );
3775  assert(consdata->nlrow != NULL);
3776  }
3777  SCIPnlrowSetCurvature(consdata->nlrow, consdata->curv);
3778  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3779  }
3780  }
3781  }
3782 
3783  /* register non linear handlers */
3784  SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3785 
3786  return SCIP_OKAY;
3787 }
3788 
3789 /** deinitializes (pre)solving data of constraints
3790  *
3791  * This removes the initialization data created in initSolve().
3792  *
3793  * This function can be called in presolve and solve.
3794  *
3795  * TODO At the moment, it should not be called for a constraint if there are other constraints
3796  * that use the same expressions but still require their nlhdlr.
3797  * We should probably only decrement the auxvar and activity usage for the root expr and then
3798  * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3799  */
3800 static
3802  SCIP* scip, /**< SCIP data structure */
3803  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3804  SCIP_CONS** conss, /**< constraints */
3805  int nconss /**< number of constraints */
3806  )
3807 {
3808  SCIP_EXPRITER* it;
3809  SCIP_EXPR* expr;
3810  SCIP_CONSDATA* consdata;
3811  SCIP_Bool rootactivityvalid;
3812  int c;
3813 
3814  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3817 
3818  /* call deinitialization callbacks of expression and nonlinear handlers
3819  * free nonlinear handlers information from expressions
3820  * remove auxiliary variables and nactivityuses counts from expressions
3821  */
3822  for( c = 0; c < nconss; ++c )
3823  {
3824  assert(conss != NULL);
3825  assert(conss[c] != NULL);
3826 
3827  consdata = SCIPconsGetData(conss[c]);
3828  assert(consdata != NULL);
3829  assert(consdata->expr != NULL);
3830 
3831  /* check and remember whether activity in root is valid */
3832  rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3833 
3834  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3835  {
3836  SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3837 
3838  /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3839  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3840 
3841  /* remove quadratic info */
3842  SCIPfreeExprQuadratic(scip, expr);
3843 
3844  if( rootactivityvalid )
3845  {
3846  /* ensure activity is valid if consdata->expr activity is valid
3847  * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3848  * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3849  * so this childs activity would be invalid, which can generate confusion
3850  */
3851  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
3852  }
3853  }
3854 
3855  if( consdata->nlrow != NULL )
3856  {
3857  /* remove row from NLP, if still in solving
3858  * if we are in exitsolve, the whole NLP will be freed anyway
3859  */
3860  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3861  {
3862  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3863  }
3864 
3865  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3866  }
3867 
3868  /* forget about linear variables that can be increased or decreased without harming feasibility */
3869  consdata->linvardecr = NULL;
3870  consdata->linvarincr = NULL;
3871 
3872  /* forget about curvature */
3873  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3874  }
3875 
3876  SCIPfreeExpriter(&it);
3877 
3878  return SCIP_OKAY;
3879 }
3880 
3881 /** helper method to decide whether a given expression is product of at least two binary variables */
3882 static
3884  SCIP* scip, /**< SCIP data structure */
3885  SCIP_EXPR* expr /**< expression */
3886  )
3887 {
3888  int i;
3889 
3890  assert(expr != NULL);
3891 
3892  /* check whether the expression is a product */
3893  if( !SCIPisExprProduct(scip, expr) )
3894  return FALSE;
3895 
3896  /* don't consider products with a coefficient != 1 and products with a single child
3897  * simplification will take care of this expression later
3898  */
3899  if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3900  return FALSE;
3901 
3902  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3903  {
3904  SCIP_EXPR* child;
3905  SCIP_VAR* var;
3906  SCIP_Real ub;
3907  SCIP_Real lb;
3908 
3909  child = SCIPexprGetChildren(expr)[i];
3910  assert(child != NULL);
3911 
3912  if( !SCIPisExprVar(scip, child) )
3913  return FALSE;
3914 
3915  var = SCIPgetVarExprVar(child);
3916  lb = SCIPvarGetLbLocal(var);
3917  ub = SCIPvarGetUbLocal(var);
3918 
3919  /* check whether variable is integer and has [0,1] as variable bounds */
3920  if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3921  return FALSE;
3922  }
3923 
3924  return TRUE;
3925 }
3926 
3927 /** helper method to collect all bilinear binary product terms */
3928 static
3930  SCIP* scip, /**< SCIP data structure */
3931  SCIP_EXPR* sumexpr, /**< sum expression */
3932  SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3933  SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3934  int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3935  int* nterms /**< pointer to store the total number of bilinear binary terms */
3936  )
3937 {
3938  int i;
3939 
3940  assert(sumexpr != NULL);
3941  assert(SCIPisExprSum(scip, sumexpr));
3942  assert(xs != NULL);
3943  assert(ys != NULL);
3944  assert(childidxs != NULL);
3945  assert(nterms != NULL);
3946 
3947  *nterms = 0;
3948 
3949  for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3950  {
3951  SCIP_EXPR* child;
3952 
3953  child = SCIPexprGetChildren(sumexpr)[i];
3954  assert(child != NULL);
3955 
3956  if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3957  {
3960 
3961  assert(x != NULL);
3962  assert(y != NULL);
3963 
3964  if( x != y )
3965  {
3966  xs[*nterms] = x;
3967  ys[*nterms] = y;
3968  childidxs[*nterms] = i;
3969  ++(*nterms);
3970  }
3971  }
3972  }
3973 
3974  return SCIP_OKAY;
3975 }
3976 
3977 /** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3978 static
3980  SCIP* scip, /**< SCIP data structure */
3981  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3982  SCIP_CONS* cons, /**< constraint */
3983  SCIP_VAR* facvar, /**< variable that has been factorized */
3984  SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3985  SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3986  int nvars, /**< total number of variables in sum_j c_ij x_j */
3987  SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3988  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3989  )
3990 {
3991  SCIP_VAR* auxvar;
3992  SCIP_CONS* newcons;
3993  SCIP_Real minact = 0.0;
3994  SCIP_Real maxact = 0.0;
3995  SCIP_Bool integral = TRUE;
3996  char name [SCIP_MAXSTRLEN];
3997  int i;
3998 
3999  assert(facvar != NULL);
4000  assert(vars != NULL);
4001  assert(nvars > 1);
4002  assert(newexpr != NULL);
4003 
4004  /* compute minimum and maximum activity of sum_j c_ij x_j */
4005  /* TODO could compute minact and maxact for facvar=0 and facvar=1 separately, taking implied bounds into account, allowing for possibly tighter big-M's below */
4006  for( i = 0; i < nvars; ++i )
4007  {
4008  minact += MIN(coefs[i], 0.0);
4009  maxact += MAX(coefs[i], 0.0);
4010  integral = integral && SCIPisIntegral(scip, coefs[i]);
4011  }
4012  assert(minact <= maxact);
4013 
4014  /* create and add auxiliary variable */
4015  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4016  SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
4017  SCIP_CALL( SCIPaddVar(scip, auxvar) );
4018 
4019  /* create and add z - maxact x <= 0 */
4020  if( !SCIPisZero(scip, maxact) )
4021  {
4022  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4023  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
4024  SCIP_CALL( SCIPaddCons(scip, newcons) );
4025  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4026  if( naddconss != NULL )
4027  ++(*naddconss);
4028  }
4029 
4030  /* create and add 0 <= z - minact x */
4031  if( !SCIPisZero(scip, minact) )
4032  {
4033  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4034  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
4035  SCIP_CALL( SCIPaddCons(scip, newcons) );
4036  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4037  if( naddconss != NULL )
4038  ++(*naddconss);
4039  }
4040 
4041  /* create and add minact <= sum_j c_j x_j - z + minact x_i */
4042  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4043  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
4044  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4045  if( !SCIPisZero(scip, minact) )
4046  {
4047  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
4048  }
4049  SCIP_CALL( SCIPaddCons(scip, newcons) );
4050  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4051  if( naddconss != NULL )
4052  ++(*naddconss);
4053 
4054  /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4055  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4056  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4057  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4058  if( !SCIPisZero(scip, maxact) )
4059  {
4060  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4061  }
4062  SCIP_CALL( SCIPaddCons(scip, newcons) );
4063  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4064  if( naddconss != NULL )
4065  ++(*naddconss);
4066 
4067  /* create variable expression */
4068  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4069 
4070  /* release auxvar */
4071  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4072 
4073  return SCIP_OKAY;
4074 }
4075 
4076 /** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4077 static
4079  SCIP* scip, /**< SCIP data structure */
4080  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4081  SCIP_CONS* cons, /**< constraint */
4082  SCIP_EXPR* sumexpr, /**< expression */
4083  int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4084  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4085  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4086  )
4087 {
4088  SCIP_EXPR** exprs = NULL;
4089  SCIP_VAR** tmpvars = NULL;
4090  SCIP_VAR** vars = NULL;
4091  SCIP_VAR** xs = NULL;
4092  SCIP_VAR** ys = NULL;
4093  SCIP_Real* exprcoefs = NULL;
4094  SCIP_Real* tmpcoefs = NULL;
4095  SCIP_Real* sumcoefs;
4096  SCIP_Bool* isused = NULL;
4097  int* childidxs = NULL;
4098  int* count = NULL;
4099  int nchildren;
4100  int nexprs = 0;
4101  int nterms;
4102  int nvars;
4103  int ntotalvars;
4104  int i;
4105 
4106  assert(sumexpr != NULL);
4107  assert(minterms > 1);
4108  assert(newexpr != NULL);
4109 
4110  *newexpr = NULL;
4111 
4112  /* check whether sumexpr is indeed a sum */
4113  if( !SCIPisExprSum(scip, sumexpr) )
4114  return SCIP_OKAY;
4115 
4116  nchildren = SCIPexprGetNChildren(sumexpr);
4117  sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4118  nvars = SCIPgetNVars(scip);
4119  ntotalvars = SCIPgetNTotalVars(scip);
4120 
4121  /* check whether there are enough terms available */
4122  if( nchildren < minterms )
4123  return SCIP_OKAY;
4124 
4125  /* allocate memory */
4126  SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4127  SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4128  SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4129 
4130  /* collect all bilinear binary product terms */
4131  SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4132 
4133  /* check whether there are enough terms available */
4134  if( nterms < minterms )
4135  goto TERMINATE;
4136 
4137  /* store how often each variable appears in a bilinear binary product */
4138  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
4139  SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4140  SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4141 
4142  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4143  SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4144  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4145  SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4146 
4147  for( i = 0; i < nterms; ++i )
4148  {
4149  int xidx;
4150  int yidx;
4151 
4152  assert(xs[i] != NULL);
4153  assert(ys[i] != NULL);
4154 
4155  xidx = SCIPvarGetIndex(xs[i]);
4156  assert(xidx < ntotalvars);
4157  yidx = SCIPvarGetIndex(ys[i]);
4158  assert(yidx < ntotalvars);
4159 
4160  ++count[xidx];
4161  ++count[yidx];
4162 
4163  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4164  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4165  }
4166 
4167  /* sort variables; don't change order of count array because it depends on problem indices */
4168  {
4169  int* tmpcount;
4170 
4171  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4172  SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4173  SCIPfreeBufferArray(scip, &tmpcount);
4174  }
4175 
4176  for( i = 0; i < nvars; ++i )
4177  {
4178  SCIP_VAR* facvar = vars[i];
4179  int ntmpvars = 0;
4180  int j;
4181 
4182  /* skip candidate if there are not enough terms left */
4183  if( count[SCIPvarGetIndex(vars[i])] < minterms )
4184  continue;
4185 
4186  SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4187 
4188  /* collect variables for x_i * sum_j c_ij x_j */
4189  for( j = 0; j < nterms; ++j )
4190  {
4191  int childidx = childidxs[j];
4192  assert(childidx >= 0 && childidx < nchildren);
4193 
4194  if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4195  {
4196  SCIP_Real coef;
4197  int xidx;
4198  int yidx;
4199 
4200  coef = sumcoefs[childidx];
4201  assert(coef != 0.0);
4202 
4203  /* collect corresponding variable */
4204  tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4205  tmpcoefs[ntmpvars] = coef;
4206  ++ntmpvars;
4207 
4208  /* update counters */
4209  xidx = SCIPvarGetIndex(xs[j]);
4210  assert(xidx < ntotalvars);
4211  yidx = SCIPvarGetIndex(ys[j]);
4212  assert(yidx < ntotalvars);
4213  --count[xidx];
4214  --count[yidx];
4215  assert(count[xidx] >= 0);
4216  assert(count[yidx] >= 0);
4217 
4218  /* mark term to be used */
4219  isused[childidx] = TRUE;
4220  }
4221  }
4222  assert(ntmpvars >= minterms);
4223  assert(SCIPvarGetIndex(facvar) < ntotalvars);
4224  assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4225 
4226  /* create required constraints and store the generated expression */
4227  SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4228  exprcoefs[nexprs] = 1.0;
4229  ++nexprs;
4230  }
4231 
4232  /* factorization was only successful if at least one expression has been generated */
4233  if( nexprs > 0 )
4234  {
4235  int nexprsold = nexprs;
4236 
4237  /* add all children of the sum that have not been used */
4238  for( i = 0; i < nchildren; ++i )
4239  {
4240  if( !isused[i] )
4241  {
4242  exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4243  exprcoefs[nexprs] = sumcoefs[i];
4244  ++nexprs;
4245  }
4246  }
4247 
4248  /* create a new sum expression */
4249  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4250 
4251  /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4252  for( i = 0; i < nexprsold; ++i )
4253  {
4254  SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4255  }
4256  }
4257 
4258 TERMINATE:
4259  /* free memory */
4260  SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4261  SCIPfreeBufferArrayNull(scip, &tmpvars);
4262  SCIPfreeBufferArrayNull(scip, &exprcoefs);
4263  SCIPfreeBufferArrayNull(scip, &exprs);
4264  SCIPfreeBufferArrayNull(scip, &vars);
4265  SCIPfreeBufferArrayNull(scip, &isused);
4266  SCIPfreeBufferArrayNull(scip, &count);
4267  SCIPfreeBufferArray(scip, &childidxs);
4268  SCIPfreeBufferArray(scip, &ys);
4269  SCIPfreeBufferArray(scip, &xs);
4270 
4271  return SCIP_OKAY;
4272 }
4273 
4274 /** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4275 static
4277  SCIP* scip, /**< SCIP data structure */
4278  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4279  SCIP_EXPR* prodexpr, /**< product expression */
4280  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4281  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4282  SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4283  )
4284 {
4285  SCIP_VAR** vars;
4286  SCIP_CONS* cons;
4287  SCIP_Real* coefs;
4288  SCIP_VAR* w;
4289  char name[SCIP_MAXSTRLEN];
4290  int nchildren;
4291  int i;
4292 
4293  assert(conshdlr != NULL);
4294  assert(prodexpr != NULL);
4295  assert(SCIPisExprProduct(scip, prodexpr));
4296  assert(newexpr != NULL);
4297 
4298  nchildren = SCIPexprGetNChildren(prodexpr);
4299  assert(nchildren >= 2);
4300 
4301  /* memory to store the variables of the variable expressions (+1 for w) */
4302  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4303  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4304 
4305  /* prepare the names of the variable and the constraints */
4306  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform");
4307  for( i = 0; i < nchildren; ++i )
4308  {
4309  vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4310  coefs[i] = 1.0;
4311  assert(vars[i] != NULL);
4312  (void) strcat(name, "_");
4313  (void) strcat(name, SCIPvarGetName(vars[i]));
4314  }
4315 
4316  /* create and add variable */
4317  SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4318  SCIP_CALL( SCIPaddVar(scip, w) );
4319  SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4320 
4321  /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4322  if( nchildren == 2 && !empathy4and )
4323  {
4324  SCIP_VAR* x = vars[0];
4325  SCIP_VAR* y = vars[1];
4326 
4327  assert(x != NULL);
4328  assert(y != NULL);
4329  assert(x != y);
4330 
4331  /* create and add x - w >= 0 */
4332  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4333  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4334  SCIP_CALL( SCIPaddCons(scip, cons) );
4335  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4336 
4337  /* create and add y - w >= 0 */
4338  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4339  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4340  SCIP_CALL( SCIPaddCons(scip, cons) );
4341  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4342 
4343  /* create and add x + y - w <= 1 */
4344  vars[2] = w;
4345  coefs[2] = -1.0;
4346  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4347  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4348  SCIP_CALL( SCIPaddCons(scip, cons) );
4349  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4350 
4351  /* update number of added constraints */
4352  if( naddconss != NULL )
4353  *naddconss += 3;
4354  }
4355  else
4356  {
4357  /* create, add, and release AND constraint */
4358  SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4359  SCIP_CALL( SCIPaddCons(scip, cons) );
4360  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4361  SCIPdebugMsg(scip, " create AND constraint\n");
4362 
4363  /* update number of added constraints */
4364  if( naddconss != NULL )
4365  *naddconss += 1;
4366  }
4367 
4368  /* create variable expression */
4369  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4370 
4371  /* release created variable */
4372  SCIP_CALL( SCIPreleaseVar(scip, &w) );
4373 
4374  /* free memory */
4375  SCIPfreeBufferArray(scip, &coefs);
4376  SCIPfreeBufferArray(scip, &vars);
4377 
4378  return SCIP_OKAY;
4379 }
4380 
4381 /** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4382 static
4384  SCIP* scip, /**< SCIP data structure */
4385  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4386  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4387  SCIP_EXPR* prodexpr, /**< product expression */
4388  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4389  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4390  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4391  )
4392 {
4393  SCIP_CONSHDLRDATA* conshdlrdata;
4394  int nchildren;
4395 
4396  assert(prodexpr != NULL);
4397  assert(newexpr != NULL);
4398 
4399  *newexpr = NULL;
4400 
4401  /* only consider products of binary variables */
4402  if( !isBinaryProduct(scip, prodexpr) )
4403  return SCIP_OKAY;
4404 
4405  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4406  assert(conshdlrdata != NULL);
4407  nchildren = SCIPexprGetNChildren(prodexpr);
4408  assert(nchildren >= 2);
4409 
4410  /* check whether there is already an expression that represents the product */
4411  if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4412  {
4413  *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4414  assert(*newexpr != NULL);
4415 
4416  /* capture expression */
4417  SCIPcaptureExpr(*newexpr);
4418  }
4419  else
4420  {
4421  SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4422 
4423  if( nchildren == 2 )
4424  {
4425  SCIP_CLIQUE** xcliques;
4426  SCIP_VAR* x;
4427  SCIP_VAR* y;
4428  SCIP_Bool found_clique = FALSE;
4429  int c;
4430 
4431  /* get variables from the product expression */
4432  x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4433  assert(x != NULL);
4434  y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4435  assert(y != NULL);
4436  assert(x != y);
4437 
4438  /* first try to find a clique containing both variables */
4439  xcliques = SCIPvarGetCliques(x, TRUE);
4440 
4441  /* look in cliques containing x */
4442  for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4443  {
4444  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4445  {
4446  /* create zero value expression */
4447  SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4448 
4449  if( nchgcoefs != NULL )
4450  *nchgcoefs += 1;
4451 
4452  found_clique = TRUE;
4453  break;
4454  }
4455 
4456  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4457  {
4458  /* create variable expression for x */
4459  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4460 
4461  if( nchgcoefs != NULL )
4462  *nchgcoefs += 2;
4463 
4464  found_clique = TRUE;
4465  break;
4466  }
4467  }
4468 
4469  if( !found_clique )
4470  {
4471  xcliques = SCIPvarGetCliques(x, FALSE);
4472 
4473  /* look in cliques containing complement of x */
4474  for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4475  {
4476  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4477  {
4478  /* create variable expression for y */
4479  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4480 
4481  if( nchgcoefs != NULL )
4482  *nchgcoefs += 1;
4483 
4484  found_clique = TRUE;
4485  break;
4486  }
4487 
4488  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4489  {
4490  /* create sum expression */
4491  SCIP_EXPR* sum_children[2];
4492  SCIP_Real sum_coefs[2];
4493  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4494  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4495  sum_coefs[0] = 1.0;
4496  sum_coefs[1] = 1.0;
4497  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4498 
4499  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4500  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4501 
4502  if( nchgcoefs != NULL )
4503  *nchgcoefs += 3;
4504 
4505  found_clique = TRUE;
4506  break;
4507  }
4508  }
4509  }
4510 
4511  /* if the variables are not in a clique, do standard linearization */
4512  if( !found_clique )
4513  {
4514  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4515  }
4516  }
4517  else
4518  {
4519  /* linearize binary product using an AND constraint because nchildren > 2 */
4520  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4521  }
4522 
4523  /* hash variable expression */
4524  SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4525  }
4526 
4527  return SCIP_OKAY;
4528 }
4529 
4530 /** helper function to replace binary products in a given constraint */
4531 static
4533  SCIP* scip, /**< SCIP data structure */
4534  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4535  SCIP_CONS* cons, /**< constraint */
4536  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4537  SCIP_EXPRITER* it, /**< expression iterator */
4538  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4539  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4540  )
4541 {
4542  SCIP_CONSHDLRDATA* conshdlrdata;
4543  SCIP_CONSDATA* consdata;
4544  SCIP_EXPR* expr;
4545 
4546  assert(conshdlr != NULL);
4547  assert(cons != NULL);
4548  assert(exprmap != NULL);
4549  assert(it != NULL);
4550 
4551  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4552  assert(conshdlrdata != NULL);
4553 
4554  consdata = SCIPconsGetData(cons);
4555  assert(consdata != NULL);
4556  assert(consdata->expr != NULL);
4557 
4558  SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4559 
4560  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4561  {
4562  SCIP_EXPR* newexpr = NULL;
4563  SCIP_EXPR* childexpr;
4564  int childexpridx;
4565 
4566  childexpridx = SCIPexpriterGetChildIdxDFS(it);
4567  assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4568  childexpr = SCIPexpriterGetChildExprDFS(it);
4569  assert(childexpr != NULL);
4570 
4571  /* try to factorize variables in a sum expression that contains several products of binary variables */
4572  if( conshdlrdata->reformbinprodsfac > 1 )
4573  {
4574  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4575  }
4576 
4577  /* try to create an expression that represents a product of binary variables */
4578  if( newexpr == NULL )
4579  {
4580  SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4581  }
4582 
4583  if( newexpr != NULL )
4584  {
4585  assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4586 
4587  /* replace product expression */
4588  SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4589 
4590  /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4591  SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4592 
4593  /* mark the constraint to not be simplified anymore */
4594  consdata->issimplified = FALSE;
4595  }
4596  }
4597 
4598  return SCIP_OKAY;
4599 }
4600 
4601 /** reformulates products of binary variables during presolving in the following way:
4602  *
4603  * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4604  * Each term \f$x_i x_j\f$ is reformulated with the help of an extra (implicit integer) variable \f$z_{ij}\f$ in {0,1}:
4605  * \f[
4606  * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4607  * \f]
4608  *
4609  * Before reformulating \f$x_i x_j\f$ in this way, it is checked whether there is a clique that contains \f$x_i\f$ and \f$x_j\f$.
4610  * These cliques allow for a better reformulation. There are four cases:
4611  *
4612  * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4613  * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4614  * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4615  * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4616  *
4617  * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4618  *
4619  * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4620  * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4621  * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4622  * Such a lower sum is reformulated with only one extra variable w_i:
4623  * \f{align}{
4624  * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4625  * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4626  * \text{minact}\, x_i & \leq w_i, \\
4627  * w_i &\leq \text{maxact}\, x_i, \\
4628  * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4629  * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4630  * \f}
4631  * We mark \f$w_i\f$ to be implicit integer if all \f$Q_{ij}\f$ are integer. After each replacement of a lower sum, it
4632  * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4633  * of terms are prioritized.
4634  */
4635 static
4637  SCIP* scip, /**< SCIP data structure */
4638  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4639  SCIP_CONS** conss, /**< constraints */
4640  int nconss, /**< total number of constraints */
4641  int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4642  int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4643  )
4644 {
4645  SCIP_CONSHDLRDATA* conshdlrdata;
4646  SCIP_HASHMAP* exprmap;
4647  SCIP_EXPRITER* it;
4648  int c;
4649 
4650  assert(conshdlr != NULL);
4651 
4652  /* no nonlinear constraints or binary variables -> skip */
4653  if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4654  return SCIP_OKAY;
4655  assert(conss != NULL);
4656 
4657  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4658  assert(conshdlrdata != NULL);
4659 
4660  /* create expression hash map */
4661  SCIP_CALL( SCIPhashmapCreate(&exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
4662 
4663  /* create expression iterator */
4664  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4667 
4668  SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4669 
4670  for( c = 0; c < nconss; ++c )
4671  {
4672  SCIP_CONSDATA* consdata;
4673  SCIP_EXPR* newexpr = NULL;
4674 
4675  assert(conss[c] != NULL);
4676 
4677  consdata = SCIPconsGetData(conss[c]);
4678  assert(consdata != NULL);
4679 
4680  /* try to reformulate the root expression */
4681  if( conshdlrdata->reformbinprodsfac > 1 )
4682  {
4683  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4684  }
4685 
4686  /* release the root node if another expression has been found */
4687  if( newexpr != NULL )
4688  {
4689  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4690  consdata->expr = newexpr;
4691 
4692  /* mark constraint to be not simplified anymore */
4693  consdata->issimplified = FALSE;
4694  }
4695 
4696  /* replace each product of binary variables separately */
4697  SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4698  }
4699 
4700  /* free memory */
4701  SCIPhashmapFree(&exprmap);
4702  SCIPfreeExpriter(&it);
4703 
4704  return SCIP_OKAY;
4705 }
4706 
4707 /** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4708  *
4709  * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4710  * Then scale by -1 if
4711  * - \f$n_+ < n_-\f$, or
4712  * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4713  */
4714 static
4716  SCIP* scip, /**< SCIP data structure */
4717  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4718  SCIP_CONS* cons, /**< nonlinear constraint */
4719  SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4720  )
4721 {
4722  SCIP_CONSDATA* consdata;
4723  int i;
4724 
4725  assert(cons != NULL);
4726 
4727  consdata = SCIPconsGetData(cons);
4728  assert(consdata != NULL);
4729 
4730  if( SCIPisExprSum(scip, consdata->expr) )
4731  {
4732  SCIP_Real* coefs;
4733  SCIP_Real constant;
4734  int nchildren;
4735  int counter = 0;
4736 
4737  coefs = SCIPgetCoefsExprSum(consdata->expr);
4738  constant = SCIPgetConstantExprSum(consdata->expr);
4739  nchildren = SCIPexprGetNChildren(consdata->expr);
4740 
4741  /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4742  if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4743  {
4744  SCIP_EXPR* expr;
4745  expr = consdata->expr;
4746 
4747  consdata->expr = SCIPexprGetChildren(expr)[0];
4748  assert(!SCIPisExprSum(scip, consdata->expr));
4749 
4750  SCIPcaptureExpr(consdata->expr);
4751 
4752  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4753  consdata->lhs = -consdata->lhs;
4754  consdata->rhs = -consdata->rhs;
4755 
4756  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4757  *changed = TRUE;
4758  return SCIP_OKAY;
4759  }
4760 
4761  /* compute n_+ - n_i */
4762  for( i = 0; i < nchildren; ++i )
4763  counter += coefs[i] > 0 ? 1 : -1;
4764 
4765  if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4766  {
4767  SCIP_EXPR* expr;
4768  SCIP_Real* newcoefs;
4769 
4770  /* allocate memory */
4771  SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4772 
4773  for( i = 0; i < nchildren; ++i )
4774  newcoefs[i] = -coefs[i];
4775 
4776  /* create a new sum expression */
4777  SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4778 
4779  /* replace expression in constraint data and scale sides */
4780  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4781  consdata->expr = expr;
4782  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4783  consdata->lhs = -consdata->lhs;
4784  consdata->rhs = -consdata->rhs;
4785 
4786  /* free memory */
4787  SCIPfreeBufferArray(scip, &newcoefs);
4788 
4789  *changed = TRUE;
4790  }
4791  }
4792 
4793  return SCIP_OKAY;
4794 }
4795 
4796 /** forbid multiaggrations of variables that appear nonlinear in constraints */
4797 static
4799  SCIP* scip, /**< SCIP data structure */
4800  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4801  SCIP_CONS** conss, /**< constraints */
4802  int nconss /**< number of constraints */
4803  )
4804 {
4805  SCIP_EXPRITER* it;
4806  SCIP_CONSDATA* consdata;
4807  SCIP_EXPR* expr;
4808  int c;
4809 
4810  assert(scip != NULL);
4811  assert(conshdlr != NULL);
4812 
4813  if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4814  return SCIP_OKAY;
4815 
4816  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4818 
4819  for( c = 0; c < nconss; ++c )
4820  {
4821  consdata = SCIPconsGetData(conss[c]);
4822  assert(consdata != NULL);
4823 
4824  /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4825  * i.e., skip children of sum that are variables
4826  */
4827  if( SCIPisExprSum(scip, consdata->expr) )
4828  {
4829  int i;
4830  SCIP_EXPR* child;
4831  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4832  {
4833  child = SCIPexprGetChildren(consdata->expr)[i];
4834 
4835  /* skip variable expression, as they correspond to a linear term */
4836  if( SCIPisExprVar(scip, child) )
4837  continue;
4838 
4839  for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4840  if( SCIPisExprVar(scip, expr) )
4841  {
4843  }
4844  }
4845  }
4846  else
4847  {
4848  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4849  if( SCIPisExprVar(scip, expr) )
4850  {
4852  }
4853  }
4854  }
4855 
4856  SCIPfreeExpriter(&it);
4857 
4858  return SCIP_OKAY;
4859 }
4860 
4861 /** simplifies expressions and replaces common subexpressions for a set of constraints
4862  * @todo put the constant to the constraint sides
4863  */
4864 static
4866  SCIP* scip, /**< SCIP data structure */
4867  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4868  SCIP_CONS** conss, /**< constraints */
4869  int nconss, /**< total number of constraints */
4870  SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4871  SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4872  int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4873  int* naddconss, /**< counter to add number of added constraints, or NULL */
4874  int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4875  )
4876 {
4877  SCIP_CONSHDLRDATA* conshdlrdata;
4878  SCIP_CONSDATA* consdata;
4879  int* nlockspos;
4880  int* nlocksneg;
4881  SCIP_Bool havechange;
4882  int i;
4883 
4884  assert(scip != NULL);
4885  assert(conshdlr != NULL);
4886  assert(conss != NULL);
4887  assert(nconss > 0);
4888  assert(infeasible != NULL);
4889 
4890  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4891  assert(conshdlrdata != NULL);
4892 
4893  /* update number of canonicalize calls */
4894  ++(conshdlrdata->ncanonicalizecalls);
4895 
4896  SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4897 
4898  *infeasible = FALSE;
4899 
4900  /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4901  havechange = conshdlrdata->ncanonicalizecalls == 1;
4902 
4903  /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4904  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4905 
4906  /* allocate memory for storing locks of each constraint */
4907  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4908  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4909 
4910  /* unlock all constraints */
4911  for( i = 0; i < nconss; ++i )
4912  {
4913  assert(conss[i] != NULL);
4914 
4915  consdata = SCIPconsGetData(conss[i]);
4916  assert(consdata != NULL);
4917 
4918  /* remember locks */
4919  nlockspos[i] = consdata->nlockspos;
4920  nlocksneg[i] = consdata->nlocksneg;
4921 
4922  /* remove locks */
4923  SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4924  assert(consdata->nlockspos == 0);
4925  assert(consdata->nlocksneg == 0);
4926  }
4927 
4928 #ifndef NDEBUG
4929  /* check whether all locks of each expression have been removed */
4930  for( i = 0; i < nconss; ++i )
4931  {
4932  SCIP_EXPR* expr;
4933  SCIP_EXPRITER* it;
4934 
4935  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4936 
4937  consdata = SCIPconsGetData(conss[i]);
4938  assert(consdata != NULL);
4939 
4940  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_RTOPOLOGIC, TRUE) );
4941  for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4942  {
4943  assert(expr != NULL);
4944  assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4945  assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4946  }
4947  SCIPfreeExpriter(&it);
4948  }
4949 #endif
4950 
4951  /* reformulate products of binary variables */
4952  if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4953  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4954  {
4955  int tmpnaddconss = 0;
4956  int tmpnchgcoefs = 0;
4957 
4958  /* call this function before simplification because expressions might not be simplified after reformulating
4959  * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4960  */
4961  SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4962 
4963  /* update counters */
4964  if( naddconss != NULL )
4965  *naddconss += tmpnaddconss;
4966  if( nchgcoefs != NULL )
4967  *nchgcoefs += tmpnchgcoefs;
4968 
4969  /* check whether at least one expression has changed */
4970  if( tmpnaddconss + tmpnchgcoefs > 0 )
4971  havechange = TRUE;
4972  }
4973 
4974  for( i = 0; i < nconss; ++i )
4975  {
4976  consdata = SCIPconsGetData(conss[i]);
4977  assert(consdata != NULL);
4978 
4979  /* call simplify for each expression */
4980  if( !consdata->issimplified && consdata->expr != NULL )
4981  {
4982  SCIP_EXPR* simplified;
4983  SCIP_Bool changed;
4984 
4985  changed = FALSE;
4986  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4987  consdata->issimplified = TRUE;
4988 
4989  if( changed )
4990  havechange = TRUE;
4991 
4992  /* If root expression changed, then we need to take care updating the locks as well (the consdata is the one holding consdata->expr "as a child").
4993  * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4994  */
4995  if( simplified != consdata->expr )
4996  {
4997  assert(changed);
4998 
4999  /* release old expression */
5000  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
5001 
5002  /* store simplified expression */
5003  consdata->expr = simplified;
5004  }
5005  else
5006  {
5007  /* The simplify captures simplified in any case, also if nothing has changed.
5008  * Therefore, we have to release it here.
5009  */
5010  SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
5011  }
5012 
5013  if( *infeasible )
5014  break;
5015 
5016  /* scale constraint sides */
5017  SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
5018 
5019  if( changed )
5020  havechange = TRUE;
5021 
5022  /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
5023  if( SCIPisExprValue(scip, consdata->expr) )
5024  {
5025  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5026  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5027  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5028  {
5029  SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5030  SCIPdebugPrintCons(scip, conss[i], NULL);
5031  *infeasible = TRUE;
5032  break;
5033  }
5034  else
5035  {
5036  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5037  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5038  if( ndelconss != NULL )
5039  ++*ndelconss;
5040  havechange = TRUE;
5041  }
5042  }
5043  }
5044  }
5045 
5046  /* replace common subexpressions */
5047  if( havechange && !*infeasible )
5048  {
5049  SCIP_CONS** consssorted;
5050  SCIP_EXPR** rootexprs;
5051  SCIP_Bool replacedroot;
5052 
5053  SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5054  for( i = 0; i < nconss; ++i )
5055  rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5056 
5057  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5058 
5059  /* update pointer to root expr in constraints, if any has changed
5060  * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5061  */
5062  if( replacedroot )
5063  for( i = 0; i < nconss; ++i )
5064  SCIPconsGetData(conss[i])->expr = rootexprs[i];
5065 
5066  SCIPfreeBufferArray(scip, &rootexprs);
5067 
5068  /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5069  * been changed after simplification; now we completely recollect all variable expression and variable events
5070  */
5071 
5072  /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5073  * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5074  */
5075  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5076  SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5077 
5078  for( i = nconss-1; i >= 0; --i )
5079  {
5080  assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5081  if( SCIPconsIsDeleted(consssorted[i]) )
5082  continue;
5083 
5084  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5085  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5086  }
5087  for( i = 0; i < nconss; ++i )
5088  {
5089  if( SCIPconsIsDeleted(consssorted[i]) )
5090  continue;
5091 
5092  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5093  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5094  }
5095 
5096  SCIPfreeBufferArray(scip, &consssorted);
5097 
5098  /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5099  * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5100  * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5101  */
5102  SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5103  }
5104 
5105  /* restore locks */
5106  for( i = 0; i < nconss; ++i )
5107  {
5108  if( SCIPconsIsDeleted(conss[i]) )
5109  continue;
5110 
5111  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5112  }
5113 
5114  /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5115  * TODO can we skip this in presoltiming fast?
5116  */
5117  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5118  {
5119  /* reset one of the number of detections counter to count only current presolving round */
5120  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5121  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5122 
5123  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5124  }
5125 
5126  /* free allocated memory */
5127  SCIPfreeBufferArray(scip, &nlocksneg);
5128  SCIPfreeBufferArray(scip, &nlockspos);
5129 
5130  SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5131 
5132  return SCIP_OKAY;
5133 }
5134 
5135 /** merges constraints that have the same root expression */
5136 static
5138  SCIP* scip, /**< SCIP data structure */
5139  SCIP_CONS** conss, /**< constraints to process */
5140  int nconss, /**< number of constraints */
5141  SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5142  )
5143 {
5144  SCIP_HASHMAP* expr2cons;
5145  SCIP_Bool* updatelocks;
5146  int* nlockspos;
5147  int* nlocksneg;
5148  int c;
5149 
5150  assert(success != NULL);
5151 
5152  *success = FALSE;
5153 
5154  /* not enough constraints available */
5155  if( nconss <= 1 )
5156  return SCIP_OKAY;
5157 
5158  SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5159  SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5160  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5161  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5162 
5163  for( c = 0; c < nconss; ++c )
5164  {
5165  SCIP_CONSDATA* consdata;
5166 
5167  /* ignore deleted constraints */
5168  if( SCIPconsIsDeleted(conss[c]) )
5169  continue;
5170 
5171  consdata = SCIPconsGetData(conss[c]);
5172  assert(consdata != NULL);
5173 
5174  /* add expression to the hash map if not seen so far */
5175  if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5176  {
5177  SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5178  }
5179  else
5180  {
5181  SCIP_CONSDATA* imgconsdata;
5182  int idx;
5183 
5184  idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5185  assert(idx >= 0 && idx < nconss);
5186 
5187  imgconsdata = SCIPconsGetData(conss[idx]);
5188  assert(imgconsdata != NULL);
5189  assert(imgconsdata->expr == consdata->expr);
5190 
5191  SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5192  SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5193 
5194  /* check whether locks need to be updated */
5195  if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5196  || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5197  {
5198  nlockspos[idx] = imgconsdata->nlockspos;
5199  nlocksneg[idx] = imgconsdata->nlocksneg;
5200  SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5201  updatelocks[idx] = TRUE;
5202  }
5203 
5204  /* update constraint sides */
5205  imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5206  imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5207 
5208  /* delete constraint */
5209  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5210  *success = TRUE;
5211  }
5212  }
5213 
5214  /* restore locks of updated constraints */
5215  if( *success )
5216  {
5217  for( c = 0; c < nconss; ++c )
5218  {
5219  if( updatelocks[c] )
5220  {
5221  SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5222  }
5223  }
5224  }
5225 
5226  /* free memory */
5227  SCIPfreeBufferArray(scip, &nlocksneg);
5228  SCIPfreeBufferArray(scip, &nlockspos);
5229  SCIPfreeBufferArray(scip, &updatelocks);
5230  SCIPhashmapFree(&expr2cons);
5231 
5232  return SCIP_OKAY;
5233 }
5234 
5235 /** interval evaluation of variables as used in redundancy check
5236  *
5237  * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5238  */
5239 static
5240 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5241 { /*lint --e{715}*/
5242  SCIP_CONSHDLRDATA* conshdlrdata;
5243  SCIP_INTERVAL interval;
5244  SCIP_Real lb;
5245  SCIP_Real ub;
5246 
5247  assert(scip != NULL);
5248  assert(var != NULL);
5249 
5250  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5251  assert(conshdlrdata != NULL);
5252 
5253  if( conshdlrdata->globalbounds )
5254  {
5255  lb = SCIPvarGetLbGlobal(var);
5256  ub = SCIPvarGetUbGlobal(var);
5257  }
5258  else
5259  {
5260  lb = SCIPvarGetLbLocal(var);
5261  ub = SCIPvarGetUbLocal(var);
5262  }
5263  assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5264 
5265  /* relax variable bounds, if there are bounds and variable is not fixed
5266  * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5267  */
5268  if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5269  {
5270  if( !SCIPisInfinity(scip, -lb) )
5271  lb -= SCIPfeastol(scip);
5272 
5273  if( !SCIPisInfinity(scip, ub) )
5274  ub += SCIPfeastol(scip);
5275  }
5276 
5277  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5278  lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
5280  assert(lb <= ub);
5281 
5282  SCIPintervalSetBounds(&interval, lb, ub);
5283 
5284  return interval;
5285 }
5286 
5287 /** removes constraints that are always feasible or very simple
5288  *
5289  * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5290  * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5291  * might violate variable bounds by up to feastol, too.
5292  * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5293  *
5294  * Also removes constraints of the form lhs &le; variable &le; rhs.
5295  *
5296  * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5297  *
5298  * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5299  * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5300  * would appear as if the constraint is redundant.
5301  */
5302 static
5304  SCIP* scip, /**< SCIP data structure */
5305  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5306  SCIP_CONS** conss, /**< constraints to propagate */
5307  int nconss, /**< total number of constraints */
5308  SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5309  int* ndelconss, /**< buffer to add the number of deleted constraints */
5310  int* nchgbds /**< buffer to add the number of variable bound tightenings */
5311  )
5312 {
5313  SCIP_CONSHDLRDATA* conshdlrdata;
5314  SCIP_CONSDATA* consdata;
5315  SCIP_INTERVAL activity;
5316  SCIP_INTERVAL sides;
5317  int i;
5318 
5319  assert(scip != NULL);
5320  assert(conshdlr != NULL);
5321  assert(conss != NULL);
5322  assert(nconss >= 0);
5323  assert(cutoff != NULL);
5324  assert(ndelconss != NULL);
5325  assert(nchgbds != NULL);
5326 
5327  /* no constraints to check */
5328  if( nconss == 0 )
5329  return SCIP_OKAY;
5330 
5331  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5332  assert(conshdlrdata != NULL);
5333 
5334  /* increase curboundstag and set lastvaractivitymethodchange
5335  * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5336  * for the redundancy check differently than for domain propagation
5337  * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5338  */
5339  ++conshdlrdata->curboundstag;
5340  assert(conshdlrdata->curboundstag > 0);
5341  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5342  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5343  conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5344 
5345  SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5346 
5347  *cutoff = FALSE;
5348  for( i = 0; i < nconss; ++i )
5349  {
5350  if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5351  continue;
5352 
5353  consdata = SCIPconsGetData(conss[i]);
5354  assert(consdata != NULL);
5355 
5356  /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5357  if( SCIPisExprValue(scip, consdata->expr) )
5358  {
5359  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5360 
5361  if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5362  (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5363  {
5364  SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5365  *cutoff = TRUE;
5366 
5367  goto TERMINATE;
5368  }
5369 
5370  SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5371 
5372  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5373  ++*ndelconss;
5374 
5375  continue;
5376  }
5377 
5378  /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5379  if( SCIPisExprVar(scip, consdata->expr) )
5380  {
5381  SCIP_VAR* var;
5382  SCIP_Bool tightened;
5383 
5384  var = SCIPgetVarExprVar(consdata->expr);
5385  assert(var != NULL);
5386 
5387  SCIPdebugMsg(scip, "variable constraint <%s> can be made redundant: <%s>[%g,%g] in [%g,%g]\n", SCIPconsGetName(conss[i]), SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), consdata->lhs, consdata->rhs);
5388 
5389  /* ensure that variable bounds are within constraint sides */
5390  if( !SCIPisInfinity(scip, -consdata->lhs) )
5391  {
5392  SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5393 
5394  if( tightened )
5395  ++*nchgbds;
5396 
5397  if( *cutoff )
5398  goto TERMINATE;
5399  }
5400 
5401  if( !SCIPisInfinity(scip, consdata->rhs) )
5402  {
5403  SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5404 
5405  if( tightened )
5406  ++*nchgbds;
5407 
5408  if( *cutoff )
5409  goto TERMINATE;
5410  }
5411 
5412  /* delete the (now) redundant constraint locally */
5413  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5414  ++*ndelconss;
5415 
5416  continue;
5417  }
5418 
5419  /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5420  * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5421  * variable bounds by up to feastol
5422  * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5423  */
5424  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5425  SCIPdebugPrintCons(scip, conss[i], NULL);
5426 
5427  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5428  assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5429 
5430  /* it is unlikely that we detect infeasibility by doing forward propagation */
5431  if( *cutoff )
5432  {
5433  SCIPdebugMsg(scip, " -> cutoff\n");
5434  goto TERMINATE;
5435  }
5436 
5437  assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5438  activity = SCIPexprGetActivity(consdata->expr);
5439 
5440  /* relax sides by feastol
5441  * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5442  */
5443  SCIPintervalSetBounds(&sides,
5444  SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5445  SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5446 
5447  if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5448  {
5449  SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5450 
5451  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5452  ++*ndelconss;
5453 
5454  continue;
5455  }
5456 
5457  SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5458  }
5459 
5460 TERMINATE:
5461  /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5462  ++conshdlrdata->curboundstag;
5463  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5464  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5465  conshdlrdata->intevalvar = intEvalVarBoundTightening;
5466 
5467  return SCIP_OKAY;
5468 }
5469 
5470 /** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5471 static
5473  SCIP* scip, /**< SCIP data structure */
5474  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5475  SCIP_CONS* cons, /**< source constraint to try to convert */
5476  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5477  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5478  int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5479  )
5480 {
5481  SCIP_CONSHDLRDATA* conshdlrdata;
5482  SCIP_CONSDATA* consdata;
5483  SCIP_CONS** upgdconss;
5484  int upgdconsssize;
5485  int nupgdconss_;
5486  int i;
5487 
5488  assert(scip != NULL);
5489  assert(conshdlr != NULL);
5490  assert(cons != NULL);
5491  assert(!SCIPconsIsModifiable(cons));
5492  assert(upgraded != NULL);
5493  assert(nupgdconss != NULL);
5494  assert(naddconss != NULL);
5495 
5496  *upgraded = FALSE;
5497 
5498  nupgdconss_ = 0;
5499 
5500  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5501  assert(conshdlrdata != NULL);
5502 
5503  /* if there are no upgrade methods, we can stop */
5504  if( conshdlrdata->nconsupgrades == 0 )
5505  return SCIP_OKAY;
5506 
5507  upgdconsssize = 2;
5508  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5509 
5510  /* call the upgrading methods */
5511  SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5512  SCIPdebugPrintCons(scip, cons, NULL);
5513 
5514  consdata = SCIPconsGetData(cons);
5515  assert(consdata != NULL);
5516 
5517  /* try all upgrading methods in priority order in case the upgrading step is enable */
5518  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5519  {
5520  if( !conshdlrdata->consupgrades[i]->active )
5521  continue;
5522 
5523  assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5524 
5525  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5526 
5527  while( nupgdconss_ < 0 )
5528  {
5529  /* upgrade function requires more memory: resize upgdconss and call again */
5530  assert(-nupgdconss_ > upgdconsssize);
5531  upgdconsssize = -nupgdconss_;
5532  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5533 
5534  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5535 
5536  assert(nupgdconss_ != 0);
5537  }
5538 
5539  if( nupgdconss_ > 0 )
5540  {
5541  /* got upgrade */
5542  int j;
5543 
5544  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5545 
5546  /* add the upgraded constraints to the problem and forget them */
5547  for( j = 0; j < nupgdconss_; ++j )
5548  {
5549  SCIPdebugMsgPrint(scip, "\t");
5550  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5551 
5552  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5553  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5554  }
5555 
5556  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5557  *nupgdconss += 1;
5558  *naddconss += nupgdconss_ - 1;
5559  *upgraded = TRUE;
5560 
5561  /* delete upgraded constraint */
5562  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5563  SCIP_CALL( SCIPdelCons(scip, cons) );
5564 
5565  break;
5566  }
5567  }
5568 
5569  SCIPfreeBufferArray(scip, &upgdconss);
5570 
5571  return SCIP_OKAY;
5572 }
5573 
5574 /** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5575  * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5576  * variable bounds, and is not binary
5577  */
5578 static
5580  SCIP* scip, /**< SCIP data structure */
5581  SCIP_EXPR* expr /**< variable expression */
5582  )
5583 {
5584  SCIP_VAR* var;
5585  SCIP_EXPR_OWNERDATA* ownerdata;
5586 
5587  assert(SCIPisExprVar(scip, expr));
5588 
5589  var = SCIPgetVarExprVar(expr);
5590  assert(var != NULL);
5591 
5592  ownerdata = SCIPexprGetOwnerData(expr);
5593  assert(ownerdata != NULL);
5594 
5595  return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5596  && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5597  && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5598  && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5600  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5601 }
5602 
5603 /** removes all variable expressions that are contained in a given expression from a hash map */
5604 static
5606  SCIP* scip, /**< SCIP data structure */
5607  SCIP_EXPR* expr, /**< expression */
5608  SCIP_EXPRITER* it, /**< expression iterator */
5609  SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5610  )
5611 {
5612  SCIP_EXPR* e;
5613 
5614  for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5615  {
5616  if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5617  {
5618  SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5619  }
5620  }
5621 
5622  return SCIP_OKAY;
5623 }
5624 
5625 /** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5626  * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5627  *
5628  * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5629  * Otherwise, a bound disjunction constraint is added.
5630  *
5631  * @todo the same reduction can be applied if g(x) is not concave, but monotone in \f$x_i\f$ for g(x) &le; rhs
5632  * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5633  * g(x) to \f$\sum_i [a_i,b_i] x^{p_i}\f$ for a single variable \f$x\f$ and try to conclude montonicity or convexity/concavity
5634  * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5635  * @todo reduction should also be applicable if variable appears in the objective with the right sign (sign such that opt is at boundary)
5636  */
5637 static
5639  SCIP* scip, /**< SCIP data structure */
5640  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5641  SCIP_CONS* cons, /**< nonlinear constraint */
5642  int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5643  int* naddconss, /**< pointer to store the total number of added constraints */
5644  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5645  )
5646 {
5647  SCIP_CONSHDLRDATA* conshdlrdata;
5648  SCIP_CONSDATA* consdata;
5649  SCIP_EXPR** singlelocked;
5650  SCIP_HASHMAP* exprcands;
5651  SCIP_Bool hasbounddisj;
5652  SCIP_Bool haslhs;
5653  SCIP_Bool hasrhs;
5654  int nsinglelocked = 0;
5655  int i;
5656 
5657  assert(conshdlr != NULL);
5658  assert(cons != NULL);
5659  assert(nchgvartypes != NULL);
5660  assert(naddconss != NULL);
5661  assert(infeasible != NULL);
5662 
5663  *nchgvartypes = 0;
5664  *naddconss = 0;
5665  *infeasible = FALSE;
5666 
5667  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5668  assert(conshdlrdata != NULL);
5669  consdata = SCIPconsGetData(cons);
5670  assert(consdata != NULL);
5671 
5672  /* only consider constraints with one finite side */
5673  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5674  return SCIP_OKAY;
5675 
5676  /* only consider sum expressions */
5677  if( !SCIPisExprSum(scip, consdata->expr) )
5678  return SCIP_OKAY;
5679 
5680  /* remember which side is finite */
5681  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5682  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5683 
5684  /* allocate memory */
5685  SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5686  SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5687 
5688  /* check all variable expressions for single locked variables */
5689  for( i = 0; i < consdata->nvarexprs; ++i )
5690  {
5691  assert(consdata->varexprs[i] != NULL);
5692 
5693  if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5694  {
5695  SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5696  singlelocked[nsinglelocked++] = consdata->varexprs[i];
5697  }
5698  }
5699  SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5700 
5701  if( nsinglelocked > 0 )
5702  {
5703  SCIP_EXPR** children;
5704  SCIP_EXPRITER* it;
5705  int nchildren;
5706 
5707  children = SCIPexprGetChildren(consdata->expr);
5708  nchildren = SCIPexprGetNChildren(consdata->expr);
5709 
5710  /* create iterator */
5711  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
5714 
5715  for( i = 0; i < nchildren; ++i )
5716  {
5717  SCIP_EXPR* child;
5718  SCIP_Real coef;
5719 
5720  child = children[i];
5721  assert(child != NULL);
5722  coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5723 
5724  /* ignore linear terms */
5725  if( SCIPisExprVar(scip, child) )
5726  continue;
5727 
5728  /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5729  * expression that represents f_j and remove each variable expression from exprcands
5730  */
5731  else if( SCIPisExprProduct(scip, child) )
5732  {
5733  int j;
5734 
5735  for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5736  {
5737  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5738 
5739  if( !SCIPisExprVar(scip, grandchild) )
5740  {
5741  /* mark all variable expressions that are contained in the expression */
5742  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5743  }
5744  }
5745  }
5746  /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5747  * for an integer k >= 1
5748  */
5749  else if( SCIPisExprPower(scip, child) )
5750  {
5751  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5752  SCIP_Real exponent = SCIPgetExponentExprPow(child);
5753  SCIP_Bool valid;
5754 
5755  /* check for even integral exponent */
5756  valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5757 
5758  if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5759  {
5760  /* mark all variable expressions that are contained in the expression */
5761  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5762  }
5763  }
5764  /* all other cases cannot be handled */
5765  else
5766  {
5767  /* mark all variable expressions that are contained in the expression */
5768  SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5769  }
5770  }
5771 
5772  /* free expression iterator */
5773  SCIPfreeExpriter(&it);
5774  }
5775 
5776  /* check whether the bound disjunction constraint handler is available */
5777  hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5778 
5779  /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5780  for( i = 0; i < nsinglelocked; ++i )
5781  {
5782  /* only consider expressions that are still contained in the exprcands map */
5783  if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5784  {
5785  SCIP_CONS* newcons;
5786  SCIP_VAR* vars[2];
5787  SCIP_BOUNDTYPE boundtypes[2];
5788  SCIP_Real bounds[2];
5789  char name[SCIP_MAXSTRLEN];
5790  SCIP_VAR* var;
5791 
5792  var = SCIPgetVarExprVar(singlelocked[i]);
5793  assert(var != NULL);
5794  SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5796 
5797  /* try to change the variable type to binary */
5798  if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5799  {
5800  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5801  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5802  ++(*nchgvartypes);
5803 
5804  if( *infeasible )
5805  {
5806  SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5807  break;
5808  }
5809  }
5810  /* add bound disjunction constraint if bounds of the variable are finite */
5811  else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5812  {
5813  vars[0] = var;
5814  vars[1] = var;
5815  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5816  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5817  bounds[0] = SCIPvarGetUbGlobal(var);
5818  bounds[1] = SCIPvarGetLbGlobal(var);
5819 
5820  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5821 
5822  /* create, add, and release bound disjunction constraint */
5823  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5824  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5825  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5826  SCIP_CALL( SCIPaddCons(scip, newcons) );
5827  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5828  ++(*naddconss);
5829  }
5830  }
5831  }
5832 
5833  /* free memory */
5834  SCIPfreeBufferArray(scip, &singlelocked);
5835  SCIPhashmapFree(&exprcands);
5836 
5837  return SCIP_OKAY;
5838 }
5839 
5840 /** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5841 static
5843  SCIP* scip, /**< SCIP data structure */
5844  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5845  SCIP_CONS** conss, /**< nonlinear constraints */
5846  int nconss, /**< total number of nonlinear constraints */
5847  int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5848  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5849  )
5850 {
5851  int c;
5852 
5853  assert(scip != NULL);
5854  assert(conshdlr != NULL);
5855  assert(conss != NULL || nconss == 0);
5856  assert(nchgvartypes != NULL);
5857  assert(infeasible != NULL);
5858 
5859  *infeasible = FALSE;
5860 
5861  /* nothing can be done if there are no binary and integer variables available */
5862  if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5863  return SCIP_OKAY;
5864 
5865  /* no continuous var can be made implicit-integer if there are no continuous variables */
5866  if( SCIPgetNContVars(scip) == 0 )
5867  return SCIP_OKAY;
5868 
5869  for( c = 0; c < nconss; ++c )
5870  {
5871  SCIP_CONSDATA* consdata;
5872  SCIP_EXPR** children;
5873  int nchildren;
5874  SCIP_Real* coefs;
5875  SCIP_EXPR* cand = NULL;
5876  SCIP_Real candcoef = 0.0;
5877  int i;
5878 
5879  assert(conss != NULL && conss[c] != NULL);
5880 
5881  consdata = SCIPconsGetData(conss[c]);
5882  assert(consdata != NULL);
5883 
5884  /* the constraint must be an equality constraint */
5885  if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5886  continue;
5887 
5888  /* the root expression needs to be a sum expression */
5889  if( !SCIPisExprSum(scip, consdata->expr) )
5890  continue;
5891 
5892  children = SCIPexprGetChildren(consdata->expr);
5893  nchildren = SCIPexprGetNChildren(consdata->expr);
5894 
5895  /* the sum expression must have at least two children
5896  * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5897  */
5898  if( nchildren <= 1 )
5899  continue;
5900 
5901  coefs = SCIPgetCoefsExprSum(consdata->expr);
5902 
5903  /* find first continuous variable and get value of its coefficient */
5904  for( i = 0; i < nchildren; ++i )
5905  {
5906  if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5907  continue;
5908 
5909  candcoef = coefs[i];
5910  assert(candcoef != 0.0);
5911 
5912  /* lhs/rhs - constant divided by candcoef must be integral
5913  * if not, break with cand == NULL, so give up
5914  */
5915  if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5916  cand = children[i];
5917 
5918  break;
5919  }
5920 
5921  /* no suitable continuous variable found */
5922  if( cand == NULL )
5923  continue;
5924 
5925  /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5926  for( i = 0; i < nchildren; ++i )
5927  {
5928  if( children[i] == cand )
5929  continue;
5930 
5931  /* child i must be integral */
5932  if( !SCIPexprIsIntegral(children[i]) )
5933  {
5934  cand = NULL;
5935  break;
5936  }
5937 
5938  /* coefficient of child i must be integral if diving by candcoef */
5939  if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5940  {
5941  cand = NULL;
5942  break;
5943  }
5944  }
5945 
5946  if( cand == NULL )
5947  continue;
5948 
5949  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5951 
5952  /* change variable type */
5953  SCIP_CALL( SCIPchgVarType(scip, SCIPgetVarExprVar(cand), SCIP_VARTYPE_IMPLINT, infeasible) );
5954 
5955  if( *infeasible )
5956  return SCIP_OKAY;
5957 
5958  /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5960  }
5961 
5962  return SCIP_OKAY;
5963 }
5964 
5965 /** creates auxiliary variable for a given expression
5966  *
5967  * @note for a variable expression it does nothing
5968  * @note this function can only be called in stage SCIP_STAGE_SOLVING
5969  */
5970 static
5972  SCIP* scip, /**< SCIP data structure */
5973  SCIP_EXPR* expr /**< expression */
5974  )
5975 {
5976  SCIP_EXPR_OWNERDATA* ownerdata;
5977  SCIP_CONSHDLRDATA* conshdlrdata;
5978  SCIP_VARTYPE vartype;
5979  SCIP_INTERVAL activity;
5980  char name[SCIP_MAXSTRLEN];
5981 
5982  assert(scip != NULL);
5983  assert(expr != NULL);
5984 
5985  ownerdata = SCIPexprGetOwnerData(expr);
5986  assert(ownerdata != NULL);
5987  assert(ownerdata->nauxvaruses > 0);
5988 
5989  /* if we already have auxvar, then do nothing */
5990  if( ownerdata->auxvar != NULL )
5991  return SCIP_OKAY;
5992 
5993  /* if expression is a variable-expression, then do nothing */
5994  if( SCIPisExprVar(scip, expr) )
5995  return SCIP_OKAY;
5996 
5997  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
5998  {
5999  SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
6000  return SCIP_INVALIDCALL;
6001  }
6002 
6003  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6004  assert(conshdlrdata != NULL);
6005  assert(conshdlrdata->auxvarid >= 0);
6006 
6007  /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6008  * but it usually indicates a missing simplify
6009  * if we find situations where we need to have an auxvar for a constant, then remove this assert
6010  */
6011  assert(!SCIPisExprValue(scip, expr));
6012 
6013  /* create and capture auxiliary variable */
6014  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6015  ++conshdlrdata->auxvarid;
6016 
6017  /* type of auxiliary variable depends on integrality information of the expression */
6019 
6020  /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6021  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6022  {
6023  activity = SCIPexprGetActivity(expr);
6024  /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6025  * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6026  * and abort in debug mode only
6027  */
6029  {
6030  SCIPABORT();
6032  }
6033  }
6034  else
6036 
6037  /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6038  * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6039  */
6040  if( SCIPgetDepth(scip) == 0 )
6041  {
6042  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
6043  }
6044  else
6045  {
6046  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
6047  }
6048 
6049  /* mark the auxiliary variable to be added for the relaxation only
6050  * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6051  * or to copy the variable to a subscip
6052  */
6053  SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6054 
6055  SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6056 
6057  SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6058 
6059  /* add variable locks in both directions
6060  * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6061  * but then we need to also update the auxvars locks when the expr locks change
6062  */
6063  SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6064 
6065 #ifdef WITH_DEBUG_SOLUTION
6066  if( SCIPdebugIsMainscip(scip) )
6067  {
6068  /* store debug solution value of auxiliary variable
6069  * assumes that expression has been evaluated in debug solution before
6070  */
6071  SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6072  }
6073 #endif
6074 
6075  if( SCIPgetDepth(scip) > 0 )
6076  {
6077  /* initialize local bounds to (locally valid) activity */
6078  SCIP_Bool cutoff;
6079  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6080  assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6081  }
6082 
6083  return SCIP_OKAY;
6084 }
6085 
6086 /** initializes separation for constraint
6087  *
6088  * - ensures that activities are up to date in all expressions
6089  * - creates auxiliary variables where required
6090  * - calls propExprDomains() to possibly tighten auxvar bounds
6091  * - calls separation initialization callback of nlhdlrs
6092  */
6093 static
6095  SCIP* scip, /**< SCIP data structure */
6096  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6097  SCIP_CONS** conss, /**< constraints */
6098  int nconss, /**< number of constraints */
6099  SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6100  )
6101 {
6102  SCIP_CONSDATA* consdata;
6103  SCIP_CONSHDLRDATA* conshdlrdata;
6104  SCIP_EXPRITER* it;
6105  SCIP_EXPR* expr;
6106  SCIP_RESULT result;
6107  SCIP_VAR* auxvar;
6108  int nreductions = 0;
6109  int c, e;
6110 
6111  assert(scip != NULL);
6112  assert(conshdlr != NULL);
6113  assert(conss != NULL || nconss == 0);
6114  assert(nconss >= 0);
6115  assert(infeasible != NULL);
6116 
6117  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6118  assert(conshdlrdata != NULL);
6119 
6120  /* start with new propbounds (just to be sure, should not be needed) */
6121  ++conshdlrdata->curpropboundstag;
6122 
6123  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6125 
6126  /* first ensure activities are up to date and create auxvars */
6127  *infeasible = FALSE;
6128  for( c = 0; c < nconss; ++c )
6129  {
6130  assert(conss != NULL);
6131  assert(conss[c] != NULL);
6132 
6133  consdata = SCIPconsGetData(conss[c]);
6134  assert(consdata != NULL);
6135  assert(consdata->expr != NULL);
6136 
6137 #ifdef WITH_DEBUG_SOLUTION
6138  if( SCIPdebugIsMainscip(scip) )
6139  {
6140  SCIP_SOL* debugsol;
6141 
6142  SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6143 
6144  if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6145  {
6146  /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6147  * in createAuxVar()
6148  */
6149  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6150  }
6151  }
6152 #endif
6153 
6154  /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6155  SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6156 
6157  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6158  {
6159  if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6160  {
6161  SCIP_CALL( createAuxVar(scip, expr) );
6162  }
6163  }
6164 
6165  auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6166  if( auxvar != NULL )
6167  {
6168  SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6169  SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6170  /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6171  SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6172  if( *infeasible )
6173  {
6174  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6175  break;
6176  }
6177 
6178  SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6179  if( *infeasible )
6180  {
6181  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6182  break;
6183  }
6184  }
6185  }
6186 
6187  /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6188  * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6189  * (e.g., log(x*y), which becomes log(w), w=x*y
6190  * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6191  */
6192  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6193  if( result == SCIP_CUTOFF )
6194  *infeasible = TRUE;
6195 
6196  /* now call initsepa of nlhdlrs
6197  * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6198  * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6199  */
6201  for( c = 0; c < nconss && !*infeasible; ++c )
6202  {
6203  assert(conss != NULL);
6204  assert(conss[c] != NULL);
6205 
6206  consdata = SCIPconsGetData(conss[c]);
6207  assert(consdata != NULL);
6208  assert(consdata->expr != NULL);
6209 
6210  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6211  {
6212  SCIP_EXPR_OWNERDATA* ownerdata;
6213 
6214  ownerdata = SCIPexprGetOwnerData(expr);
6215  assert(ownerdata != NULL);
6216 
6217  if( ownerdata->nauxvaruses == 0 )
6218  continue;
6219 
6220  for( e = 0; e < ownerdata->nenfos; ++e )
6221  {
6222  SCIP_NLHDLR* nlhdlr;
6223  SCIP_Bool underestimate;
6224  SCIP_Bool overestimate;
6225  assert(ownerdata->enfos[e] != NULL);
6226 
6227  /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6228  * which participated in a previous initSepa() call
6229  */
6230  if( ownerdata->enfos[e]->issepainit )
6231  continue;
6232 
6233  /* only call initsepa if it will actually separate */
6234  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6235  continue;
6236 
6237  nlhdlr = ownerdata->enfos[e]->nlhdlr;
6238  assert(nlhdlr != NULL);
6239 
6240  /* only init sepa if there is an initsepa callback */
6241  if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6242  continue;
6243 
6244  /* check whether expression needs to be under- or overestimated */
6245  overestimate = ownerdata->nlocksneg > 0;
6246  underestimate = ownerdata->nlockspos > 0;
6247  assert(underestimate || overestimate);
6248 
6249  SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6250 
6251  /* call the separation initialization callback of the nonlinear handler */
6252  SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6253  ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6254  ownerdata->enfos[e]->issepainit = TRUE;
6255 
6256  if( *infeasible )
6257  {
6258  /* stop everything if we detected infeasibility */
6259  SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6260  break;
6261  }
6262  }
6263  }
6264  }
6265 
6266  SCIPfreeExpriter(&it);
6267 
6268  return SCIP_OKAY;
6269 }
6270 
6271 /** returns whether we are ok to branch on auxiliary variables
6272  *
6273  * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6274  */
6275 static
6277  SCIP* scip, /**< SCIP data structure */
6278  SCIP_CONSHDLR* conshdlr /**< constraint handler */
6279  )
6280 {
6281  SCIP_CONSHDLRDATA* conshdlrdata;
6282 
6283  assert(conshdlr != NULL);
6284 
6285  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6286  assert(conshdlrdata != NULL);
6287 
6288  return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6289 }
6290 
6291 /** gets weight of variable when splitting violation score onto several variables in an expression */
6292 static
6294  SCIP* scip, /**< SCIP data structure */
6295  SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6296  SCIP_VAR* var, /**< variable */
6297  SCIP_SOL* sol /**< current solution */
6298  )
6299 {
6300  SCIP_CONSHDLRDATA* conshdlrdata;
6301 
6302  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6303  assert(conshdlrdata != NULL);
6304 
6305  switch( conshdlrdata->branchviolsplit )
6306  {
6307  case 'u' : /* uniform: everyone gets the same score */
6308  return 1.0;
6309 
6310  case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6311  {
6312  SCIP_Real weight;
6313  weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6314  return MAX(0.05, weight);
6315  }
6316 
6317  case 'd' : /* domain width */
6318  return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6319 
6320  case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6321  {
6322  SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6323  assert(width > 0.0);
6324  if( width > 10.0 )
6325  return 10.0*log10(width);
6326  if( width < 0.1 )
6327  return 0.1/(-log10(width));
6328  return width;
6329  }
6330 
6331  default :
6332  SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6333  SCIPABORT();
6334  return SCIP_INVALID;
6335  }
6336 }
6337 
6338 /** adds violation-branching score to a set of expressions, thereby distributing the score
6339  *
6340  * Each expression must either be a variable expression or have an aux-variable.
6341  *
6342  * If unbounded variables are present, each unbounded var gets an even score.
6343  * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6344  */
6345 static
6346 void addExprsViolScore(
6347  SCIP* scip, /**< SCIP data structure */
6348  SCIP_EXPR** exprs, /**< expressions where to add branching score */
6349  int nexprs, /**< number of expressions */
6350  SCIP_Real violscore, /**< violation-branching score to add to expression */
6351  SCIP_SOL* sol, /**< current solution */
6352  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6353  )
6354 {
6355  SCIP_CONSHDLR* conshdlr;
6356  SCIP_VAR* var;
6357  SCIP_Real weight;
6358  SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6359  int nunbounded = 0; /* number of candidates with unbounded domain */
6360  int i;
6361 
6362  assert(exprs != NULL);
6363  assert(nexprs > 0);
6364  assert(success != NULL);
6365 
6366  if( nexprs == 1 )
6367  {
6368  SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6369  SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6371  *success = TRUE;
6372  return;
6373  }
6374 
6375  conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6376 
6377  for( i = 0; i < nexprs; ++i )
6378  {
6379  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6380  assert(var != NULL);
6381 
6382  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6383  ++nunbounded;
6384  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6385  weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6386  }
6387 
6388  *success = FALSE;
6389  for( i = 0; i < nexprs; ++i )
6390  {
6391  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6392  assert(var != NULL);
6393 
6394  if( nunbounded > 0 )
6395  {
6396  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6397  {
6398  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6399  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6400  100.0/nunbounded, violscore,
6402  *success = TRUE;
6403  }
6404  }
6405  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6406  {
6407  assert(weightsum > 0.0);
6408 
6409  weight = getViolSplitWeight(scip, conshdlr, var, sol);
6410  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6411  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6412  100*weight / weightsum, violscore,
6414  *success = TRUE;
6415  }
6416  else
6417  {
6418  SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6420  }
6421  }
6422 }
6423 
6424 /** adds violation-branching score to children of expression for given auxiliary variables
6425  *
6426  * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6427  * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6428  *
6429  * @note This method may modify the given auxvars array by means of sorting.
6430  */
6431 static
6433  SCIP* scip, /**< SCIP data structure */
6434  SCIP_EXPR* expr, /**< expression where to start searching */
6435  SCIP_Real violscore, /**< violation score to add to expression */
6436  SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6437  int nauxvars, /**< number of auxiliary variables */
6438  SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6439  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6440  )
6441 {
6442  SCIP_EXPRITER* it;
6443  SCIP_VAR* auxvar;
6444  SCIP_EXPR** exprs;
6445  int nexprs;
6446  int pos;
6447 
6448  assert(scip != NULL);
6449  assert(expr != NULL);
6450  assert(auxvars != NULL);
6451  assert(success != NULL);
6452 
6453  /* sort variables to make lookup below faster */
6454  SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6455 
6456  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6458 
6459  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6460  nexprs = 0;
6461 
6462  for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6463  {
6464  auxvar = SCIPgetExprAuxVarNonlinear(expr);
6465  if( auxvar == NULL )
6466  continue;
6467 
6468  /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6469  if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6470  {
6471  assert(auxvars[pos] == auxvar);
6472 
6473  SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6474  exprs[nexprs++] = expr;
6475 
6476  if( nexprs == nauxvars )
6477  break;
6478  }
6479  }
6480 
6481  SCIPfreeExpriter(&it);
6482 
6483  if( nexprs > 0 )
6484  {
6485  SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6486  }
6487  else
6488  *success = FALSE;
6489 
6490  SCIPfreeBufferArray(scip, &exprs);
6491 
6492  return SCIP_OKAY;
6493 }
6494 
6495 /** registers all unfixed variables in violated constraints as branching candidates */
6496 static
6498  SCIP* scip, /**< SCIP data structure */
6499  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6500  SCIP_CONS** conss, /**< constraints */
6501  int nconss, /**< number of constraints */
6502  int* nnotify /**< counter for number of notifications performed */
6503  )
6504 {
6505  SCIP_CONSDATA* consdata;
6506  SCIP_VAR* var;
6507  int c;
6508  int i;
6509 
6510  assert(conshdlr != NULL);
6511  assert(conss != NULL || nconss == 0);
6512  assert(nnotify != NULL);
6513 
6514  *nnotify = 0;
6515 
6516  for( c = 0; c < nconss; ++c )
6517  {
6518  assert(conss != NULL && conss[c] != NULL);
6519 
6520  consdata = SCIPconsGetData(conss[c]);
6521  assert(consdata != NULL);
6522 
6523  /* consider only violated constraints */
6524  if( !isConsViolated(scip, conss[c]) )
6525  continue;
6526 
6527  /* register all variables that have not been fixed yet */
6528  assert(consdata->varexprs != NULL);
6529  for( i = 0; i < consdata->nvarexprs; ++i )
6530  {
6531  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6532  assert(var != NULL);
6533 
6534  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6535  {
6537  ++(*nnotify);
6538  }
6539  }
6540  }
6541 
6542  return SCIP_OKAY;
6543 }
6544 
6545 /** registers all variables in violated constraints with branching scores as external branching candidates */
6546 static
6548  SCIP* scip, /**< SCIP data structure */
6549  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6550  SCIP_CONS** conss, /**< constraints */
6551  int nconss, /**< number of constraints */
6552  SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6553  )
6554 {
6555  SCIP_CONSDATA* consdata;
6556  SCIP_EXPRITER* it = NULL;
6557  int c;
6558 
6559  assert(conshdlr != NULL);
6560  assert(success != NULL);
6561 
6562  *success = FALSE;
6563 
6564  if( branchAuxNonlinear(scip, conshdlr) )
6565  {
6566  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6568  }
6569 
6570  /* register external branching candidates */
6571  for( c = 0; c < nconss; ++c )
6572  {
6573  assert(conss != NULL && conss[c] != NULL);
6574 
6575  consdata = SCIPconsGetData(conss[c]);
6576  assert(consdata != NULL);
6577  assert(consdata->varexprs != NULL);
6578 
6579  /* consider only violated constraints */
6580  if( !isConsViolated(scip, conss[c]) )
6581  continue;
6582 
6583  if( !branchAuxNonlinear(scip, conshdlr) )
6584  {
6585  int i;
6586 
6587  /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6588  * only, so we can loop over variable expressions
6589  */
6590  for( i = 0; i < consdata->nvarexprs; ++i )
6591  {
6592  SCIP_Real violscore;
6593  SCIP_Real lb;
6594  SCIP_Real ub;
6595  SCIP_VAR* var;
6596 
6597  violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6598 
6599  /* skip variable expressions that do not have a violation score */
6600  if( violscore == 0.0 )
6601  continue;
6602 
6603  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6604  assert(var != NULL);
6605 
6606  lb = SCIPvarGetLbLocal(var);
6607  ub = SCIPvarGetUbLocal(var);
6608 
6609  /* consider variable for branching if it has not been fixed yet */
6610  if( !SCIPisEQ(scip, lb, ub) )
6611  {
6612  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6613  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6614  *success = TRUE;
6615  }
6616  else
6617  {
6618  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6619  }
6620 
6621  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6622  * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6623  */
6624  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6625  }
6626  }
6627  else
6628  {
6629  SCIP_EXPR* expr;
6630  SCIP_VAR* var;
6631  SCIP_Real lb;
6632  SCIP_Real ub;
6633  SCIP_Real violscore;
6634 
6635  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6636  {
6637  violscore = SCIPgetExprViolScoreNonlinear(expr);
6638  if( violscore == 0.0 )
6639  continue;
6640 
6641  /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6642  * variable, so this expression should either be an original variable or have an auxiliary variable
6643  */
6644  var = SCIPgetExprAuxVarNonlinear(expr);
6645  assert(var != NULL);
6646 
6647  lb = SCIPvarGetLbLocal(var);
6648  ub = SCIPvarGetUbLocal(var);
6649 
6650  /* consider variable for branching if it has not been fixed yet */
6651  if( !SCIPisEQ(scip, lb, ub) )
6652  {
6653  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6654 
6655  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6656  *success = TRUE;
6657  }
6658  else
6659  {
6660  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6661  }
6662  }
6663  }
6664  }
6665 
6666  if( it != NULL )
6667  SCIPfreeExpriter(&it);
6668 
6669  return SCIP_OKAY;
6670 }
6671 
6672 /** collect branching candidates from violated constraints
6673  *
6674  * Fills array with expressions that serve as branching candidates.
6675  * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6676  * branching candidate.
6677  *
6678  * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6679  * through variable-expressions only.
6680  */
6681 static
6683  SCIP* scip, /**< SCIP data structure */
6684  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6685  SCIP_CONS** conss, /**< constraints to process */
6686  int nconss, /**< number of constraints */
6687  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6688  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6689  SCIP_Longint soltag, /**< tag of solution */
6690  BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6691  int* ncands /**< number of candidates found */
6692  )
6693 {
6694  SCIP_CONSHDLRDATA* conshdlrdata;
6695  SCIP_CONSDATA* consdata;
6696  SCIP_EXPRITER* it = NULL;
6697  int c;
6698  int attempt;
6699  SCIP_VAR* var;
6700 
6701  assert(scip != NULL);
6702  assert(conshdlr != NULL);
6703  assert(cands != NULL);
6704  assert(ncands != NULL);
6705 
6706  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6707  assert(conshdlrdata != NULL);
6708 
6709  if( branchAuxNonlinear(scip, conshdlr) )
6710  {
6711  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6713  }
6714 
6715  *ncands = 0;
6716  for( attempt = 0; attempt < 2; ++attempt )
6717  {
6718  /* collect branching candidates from violated constraints
6719  * in the first attempt, consider only constraints with large violation
6720  * in the second attempt, consider all remaining violated constraints
6721  */
6722  for( c = 0; c < nconss; ++c )
6723  {
6724  SCIP_Real consviol;
6725 
6726  assert(conss != NULL && conss[c] != NULL);
6727 
6728  /* consider only violated constraints */
6729  if( !isConsViolated(scip, conss[c]) )
6730  continue;
6731 
6732  consdata = SCIPconsGetData(conss[c]);
6733  assert(consdata != NULL);
6734  assert(consdata->varexprs != NULL);
6735 
6736  SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6737 
6738  if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6739  continue;
6740  else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6741  continue;
6742 
6743  if( !branchAuxNonlinear(scip, conshdlr) )
6744  {
6745  int i;
6746 
6747  /* if not branching on auxvars, then violation-branching scores will be available for original variables
6748  * only, so we can loop over variable expressions
6749  * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6750  * variable, therefore we invalidate the score of a variable after processing it.
6751  */
6752  for( i = 0; i < consdata->nvarexprs; ++i )
6753  {
6754  SCIP_Real lb;
6755  SCIP_Real ub;
6756 
6757  /* skip variable expressions that do not have a valid violation score */
6758  if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6759  continue;
6760 
6761  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6762  assert(var != NULL);
6763 
6764  lb = SCIPvarGetLbLocal(var);
6765  ub = SCIPvarGetUbLocal(var);
6766 
6767  /* skip already fixed variable */
6768  if( SCIPisEQ(scip, lb, ub) )
6769  {
6770  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6771  continue;
6772  }
6773 
6774  assert(*ncands + 1 < SCIPgetNVars(scip));
6775  cands[*ncands].expr = consdata->varexprs[i];
6776  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6777  ++(*ncands);
6778 
6779  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6780  * several times as external branching candidate */
6781  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6782  }
6783  }
6784  else
6785  {
6786  SCIP_EXPR* expr;
6787  SCIP_Real lb;
6788  SCIP_Real ub;
6789 
6790  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6791  {
6792  if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6793  continue;
6794 
6795  /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6796  * variables, so this expression should either be an original variable or have an auxiliary variable
6797  */
6798  var = SCIPgetExprAuxVarNonlinear(expr);
6799  assert(var != NULL);
6800 
6801  lb = SCIPvarGetLbLocal(var);
6802  ub = SCIPvarGetUbLocal(var);
6803 
6804  /* skip already fixed variable */
6805  if( SCIPisEQ(scip, lb, ub) )
6806  {
6807  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6808  continue;
6809  }
6810 
6811  assert(*ncands + 1 < SCIPgetNVars(scip));
6812  cands[*ncands].expr = expr;
6813  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6814  ++(*ncands);
6815  }
6816  }
6817  }
6818 
6819  /* if we have branching candidates, then we don't need another attempt */
6820  if( *ncands > 0 )
6821  break;
6822  }
6823 
6824  if( it != NULL )
6825  SCIPfreeExpriter(&it);
6826 
6827  return SCIP_OKAY;
6828 }
6829 
6830 /** computes a branching score for a variable that reflects how important branching on this variable would be for
6831  * improving the dual bound from the LP relaxation
6832  *
6833  * Assume the Lagrangian for the current LP is something of the form
6834  * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6835  * where x are the original variables, z the auxiliary variables,
6836  * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6837  *
6838  * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6839  * If we could have used not only an estimator, but the actual function f(x), then this would
6840  * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6841  * Using a lot of handwaving, we claim that
6842  * lambda_i * (f(x) - a_i'x + b_i)
6843  * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6844  * If an estimator depended on local bounds, then it could be improved by branching.
6845  * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6846  *
6847  * 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.
6848  * To scale, we divide by the LP objective value (if >1).
6849  *
6850  * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6851  * these are affected by the bounds on original variables indirectly (through forward-propagation)
6852  *
6853  * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6854  * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6855  * would also be branching candidates
6856  */
6857 static
6859  SCIP* scip, /**< SCIP data structure */
6860  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6861  SCIP_VAR* var /**< variable */
6862  )
6863 {
6864  SCIP_COL* col;
6865  SCIP_ROW** rows;
6866  int nrows;
6867  int r;
6868  SCIP_Real dualscore;
6869 
6870  assert(scip != NULL);
6871  assert(conshdlr != NULL);
6872  assert(var != NULL);
6873 
6874  /* if LP not solved, then the dual branching score is not available */
6876  return 0.0;
6877 
6878  /* if var is not in the LP, then the dual branching score is not available */
6880  return 0.0;
6881 
6882  col = SCIPvarGetCol(var);
6883  assert(col != NULL);
6884 
6885  if( !SCIPcolIsInLP(col) )
6886  return 0.0;
6887 
6888  nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6889  rows = SCIPcolGetRows(col);
6890 
6891  /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6892 
6893  /* aggregate duals from all rows from consexpr with non-zero dual
6894  * TODO: this is a quick-and-dirty implementation, and not used by default
6895  * in the long run, this should be either removed or replaced by a proper implementation
6896  */
6897  dualscore = 0.0;
6898  for( r = 0; r < nrows; ++r )
6899  {
6900  SCIP_Real estimategap;
6901  const char* estimategapstr;
6902 
6903  /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6904  * these would typically be local, unless they are created at the root node
6905  * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6906  if( !SCIProwIsLocal(rows[r]) )
6907  continue;
6908  */
6909  if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6910  continue;
6911  if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6912  continue;
6913 
6914  estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6915  if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6916  continue;
6917  estimategap = atof(estimategapstr + 13);
6918  assert(estimategap >= 0.0);
6919  if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6920  estimategap = SCIPgetHugeValue(scip);
6921 
6922  /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6923  SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6924 
6925  dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6926  }
6927 
6928  /* divide by optimal value of LP for scaling */
6929  dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6930 
6931  return dualscore;
6932 }
6933 
6934 /** computes branching scores (including weighted score) for a set of candidates
6935  *
6936  * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6937  * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6938  *
6939  * For each score, compute the maximum over all candidates.
6940  *
6941  * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6942  * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6943  * score of all candidates.
6944  * Further divide by the sum of all weights where a score was available (even if the score was 0).
6945  *
6946  * For example:
6947  * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6948  * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6949  * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6950  * - 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.
6951  * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6952  */
6953 static
6955  SCIP* scip, /**< SCIP data structure */
6956  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6957  BRANCHCAND* cands, /**< branching candidates */
6958  int ncands, /**< number of candidates */
6959  SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6960  )
6961 {
6962  SCIP_CONSHDLRDATA* conshdlrdata;
6963  BRANCHCAND maxscore;
6964  int c;
6965 
6966  assert(scip != NULL);
6967  assert(conshdlr != NULL);
6968  assert(cands != NULL);
6969  assert(ncands > 0);
6970 
6971  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6972  assert(conshdlrdata != NULL);
6973 
6974  /* initialize counts to 0 */
6975  memset(&maxscore, 0, sizeof(BRANCHCAND));
6976 
6977  for( c = 0; c < ncands; ++c )
6978  {
6979  if( conshdlrdata->branchviolweight > 0.0 )
6980  {
6981  /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6982  maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6983  }
6984 
6985  if( conshdlrdata->branchdomainweight > 0.0 )
6986  {
6987  SCIP_Real domainwidth;
6988  SCIP_VAR* var;
6989 
6990  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6991  assert(var != NULL);
6992 
6993  /* get domain width, taking infinity at 1e20 on purpose */
6994  domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6995 
6996  /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6997  * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
6998  * the idea is to penalize very large and very small domains
6999  */
7000  if( domainwidth >= 1.0 )
7001  cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7002  else
7003  cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
7004 
7005  maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7006  }
7007  else
7008  cands[c].domain = 0.0;
7009 
7010  if( conshdlrdata->branchdualweight > 0.0 )
7011  {
7012  SCIP_VAR* var;
7013 
7014  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7015  assert(var != NULL);
7016 
7017  cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7018  maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7019  }
7020 
7021  if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7022  {
7023  SCIP_VAR* var;
7024 
7025  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7026  assert(var != NULL);
7027 
7028  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
7029  cands[c].pscost = SCIP_INVALID;
7030  else
7031  {
7032  SCIP_Real brpoint;
7033  SCIP_Real pscostdown;
7034  SCIP_Real pscostup;
7035  char strategy;
7036 
7037  /* decide how to compute pseudo-cost scores
7038  * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7039  * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7040  */
7042  strategy = conshdlrdata->branchpscostupdatestrategy;
7043  else
7044  strategy = 'l';
7045 
7046  brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7047 
7048  /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7049  * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7050  * For here, I use a simple #counts >= branchpscostreliable.
7051  * TODO use SCIPgetVarPseudocostCount() instead?
7052  */
7053  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7054  {
7055  switch( strategy )
7056  {
7057  case 's' :
7058  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7059  break;
7060  case 'd' :
7061  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7062  break;
7063  case 'l' :
7064  if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7065  pscostdown = SCIP_INVALID;
7066  else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7067  pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7068  else
7069  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, NULL, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7070  break;
7071  default :
7072  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7073  pscostdown = SCIP_INVALID;
7074  }
7075  }
7076  else
7077  pscostdown = SCIP_INVALID;
7078 
7079  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7080  {
7081  switch( strategy )
7082  {
7083  case 's' :
7084  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7085  break;
7086  case 'd' :
7087  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7088  break;
7089  case 'l' :
7090  if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7091  pscostup = SCIP_INVALID;
7092  else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7093  pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7094  else
7095  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, NULL, var) );
7096  break;
7097  default :
7098  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7099  pscostup = SCIP_INVALID;
7100  }
7101  }
7102  else
7103  pscostup = SCIP_INVALID;
7104 
7105  /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7106  * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7107  */
7108  if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7109  cands[c].pscost = SCIP_INVALID;
7110  else if( pscostdown == SCIP_INVALID )
7111  cands[c].pscost = pscostup;
7112  else if( pscostup == SCIP_INVALID )
7113  cands[c].pscost = pscostdown;
7114  else
7115  cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7116  }
7117 
7118  if( cands[c].pscost != SCIP_INVALID )
7119  maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7120  }
7121 
7122  if( conshdlrdata->branchvartypeweight > 0.0 )
7123  {
7124  SCIP_VAR* var;
7125 
7126  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7127  assert(var != NULL);
7128 
7129  switch( SCIPvarGetType(var) )
7130  {
7131  case SCIP_VARTYPE_BINARY :
7132  cands[c].vartype = 1.0;
7133  break;
7134  case SCIP_VARTYPE_INTEGER :
7135  cands[c].vartype = 0.1;
7136  break;
7137  case SCIP_VARTYPE_IMPLINT :
7138  cands[c].vartype = 0.01;
7139  break;
7141  default:
7142  cands[c].vartype = 0.0;
7143  }
7144  maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7145  }
7146  }
7147 
7148  /* now compute a weighted score for each candidate from the single scores
7149  * the single scores are scaled to be in [0,1] for this
7150  */
7151  for( c = 0; c < ncands; ++c )
7152  {
7153  SCIP_Real weightsum;
7154 
7155  ENFOLOG(
7156  SCIP_VAR* var;
7157  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7158  SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7159  )
7160 
7161  cands[c].weighted = 0.0;
7162  weightsum = 0.0;
7163 
7164  if( maxscore.auxviol > 0.0 )
7165  {
7166  cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7167  weightsum += conshdlrdata->branchviolweight;
7168 
7169  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7170  }
7171 
7172  if( maxscore.domain > 0.0 )
7173  {
7174  cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7175  weightsum += conshdlrdata->branchdomainweight;
7176 
7177  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7178  }
7179 
7180  if( maxscore.dual > 0.0 )
7181  {
7182  cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7183  weightsum += conshdlrdata->branchdualweight;
7184 
7185  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7186  }
7187 
7188  if( maxscore.pscost > 0.0 )
7189  {
7190  /* use pseudo-costs only if available */
7191  if( cands[c].pscost != SCIP_INVALID )
7192  {
7193  cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7194  weightsum += conshdlrdata->branchpscostweight;
7195 
7196  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7197  }
7198  else
7199  {
7200  /* do not add pscostscore, if not available, also do not add into weightsum */
7201  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7202  }
7203  }
7204 
7205  if( maxscore.vartype > 0.0 )
7206  {
7207  cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7208  weightsum += conshdlrdata->branchvartypeweight;
7209 
7210  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7211  }
7212  assert(weightsum > 0.0); /* we should have got at least one valid score */
7213  cands[c].weighted /= weightsum;
7214 
7215  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7216  }
7217 }
7218 
7219 /** compare two branching candidates by their weighted score
7220  *
7221  * if weighted score is equal, use variable index of (aux)var
7222  */
7223 static
7224 SCIP_DECL_SORTINDCOMP(branchcandCompare)
7226  BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7227 
7228  if( cands[ind1].weighted != cands[ind2].weighted )
7229  return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7230  else
7231  return SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind1].expr)) - SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind2].expr));
7232 }
7233 
7234 /** do branching or register branching candidates */
7235 static
7237  SCIP* scip, /**< SCIP data structure */
7238  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7239  SCIP_CONS** conss, /**< constraints to process */
7240  int nconss, /**< number of constraints */
7241  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7242  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7243  SCIP_Longint soltag, /**< tag of solution */
7244  SCIP_RESULT* result /**< pointer to store the result of branching */
7245  )
7246 {
7247  SCIP_CONSHDLRDATA* conshdlrdata;
7248  BRANCHCAND* cands;
7249  int ncands;
7250  SCIP_VAR* var;
7251  SCIP_NODE* downchild;
7252  SCIP_NODE* eqchild;
7253  SCIP_NODE* upchild;
7254 
7255  assert(conshdlr != NULL);
7256  assert(result != NULL);
7257 
7258  *result = SCIP_DIDNOTFIND;
7259 
7260  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7261  assert(conshdlrdata != NULL);
7262 
7263  if( conshdlrdata->branchexternal )
7264  {
7265  /* just register branching candidates as external */
7266  SCIP_Bool success;
7267 
7268  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7269  if( success )
7270  *result = SCIP_INFEASIBLE;
7271 
7272  return SCIP_OKAY;
7273  }
7274 
7275  /* collect branching candidates and their auxviol-score */
7276  SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip)) );
7277  SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7278 
7279  /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7280  * we will return here and let the fallbacks in consEnfo() decide how to proceed
7281  */
7282  if( ncands == 0 )
7283  goto TERMINATE;
7284 
7285  if( ncands > 1 )
7286  {
7287  /* if there are more than one candidate, then compute scores and select */
7288  int* perm;
7289  int c;
7290  int left;
7291  int right;
7292  SCIP_Real threshold;
7293 
7294  /* compute additional scores on branching candidates and weighted score */
7295  scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7296 
7297  /* sort candidates by weighted score */
7298  SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7299  SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7300 
7301  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7302  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7303  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7304 
7305  /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7306  left = 0;
7307  right = ncands - 1;
7308  threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7309  while( left < right )
7310  {
7311  int mid = (left + right) / 2;
7312  if( cands[perm[mid]].weighted >= threshold )
7313  left = mid + 1;
7314  else
7315  right = mid;
7316  }
7317  assert(left <= ncands);
7318 
7319  if( left < ncands )
7320  {
7321  if( cands[perm[left]].weighted >= threshold )
7322  {
7323  assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7324  ncands = left + 1;
7325  }
7326  else
7327  {
7328  assert(cands[perm[left]].weighted < threshold);
7329  ncands = left;
7330  }
7331  }
7332  assert(ncands > 0);
7333 
7334  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7335  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7336  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7337 
7338  if( ncands > 1 )
7339  {
7340  /* choose at random from candidates 0..ncands-1 */
7341  if( conshdlrdata->branchrandnumgen == NULL )
7342  {
7343  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7344  }
7345  c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7346  var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7347  }
7348  else
7349  var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7350 
7351  SCIPfreeBufferArray(scip, &perm);
7352  }
7353  else
7354  {
7355  var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7356  }
7357  assert(var != NULL);
7358 
7359  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7360  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); )
7361 
7362  SCIP_CALL( SCIPbranchVarVal(scip, var, SCIPgetBranchingPoint(scip, var, SCIP_INVALID), &downchild, &eqchild,
7363  &upchild) );
7364  if( downchild != NULL || eqchild != NULL || upchild != NULL )
7365  *result = SCIP_BRANCHED;
7366  else
7367  /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7368  *result = SCIP_REDUCEDDOM;
7369 
7370  TERMINATE:
7371  SCIPfreeBufferArray(scip, &cands);
7372 
7373  return SCIP_OKAY;
7374 }
7375 
7376 /** call enforcement or estimate callback of nonlinear handler
7377  *
7378  * Calls the enforcement callback, if available.
7379  * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7380  *
7381  * If cut is weak, but estimator is not tight, tries to add branching candidates.
7382  */
7383 static
7385  SCIP* scip, /**< SCIP main data structure */
7386  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7387  SCIP_CONS* cons, /**< nonlinear constraint */
7388  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7389  SCIP_EXPR* expr, /**< expression */
7390  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7391  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7392  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7393  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7394  SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7395  SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7396  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7397  SCIP_RESULT* result /**< pointer to store the result */
7398  )
7399 {
7400  assert(result != NULL);
7401 
7402  /* call enforcement callback of the nlhdlr */
7403  SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7404  allowweakcuts, separated, inenforcement, result) );
7405 
7406  /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7407  if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7408  {
7409  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr %s succeeded with result %d\n",
7410  SCIPnlhdlrGetName(nlhdlr), *result); )
7411  return SCIP_OKAY;
7412  }
7413  else
7414  {
7415  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7416  }
7417 
7418  *result = SCIP_DIDNOTFIND;
7419 
7420  /* now call the estimator callback of the nlhdlr */
7421  if( SCIPnlhdlrHasEstimate(nlhdlr) )
7422  {
7423  SCIP_VAR* auxvar;
7424  SCIP_Bool sepasuccess = FALSE;
7425  SCIP_Bool branchscoresuccess = FALSE;
7426  SCIP_PTRARRAY* rowpreps;
7427  int minidx;
7428  int maxidx;
7429  int r;
7430  SCIP_ROWPREP* rowprep;
7431 
7432  SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7433 
7434  auxvar = SCIPgetExprAuxVarNonlinear(expr);
7435  assert(auxvar != NULL);
7436 
7437  SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7438  SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7439 
7440  minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7441  maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7442 
7443  assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7444 
7445  if( !sepasuccess )
7446  {
7447  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7448  SCIPnlhdlrGetName(nlhdlr)); )
7449  }
7450 
7451  for( r = minidx; r <= maxidx; ++r )
7452  {
7453  rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7454 
7455  assert(rowprep != NULL);
7456  assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7457 
7458  /* complete estimator to cut */
7459  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7460 
7461  /* add the cut and/or branching scores */
7462  SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7463  auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7464 
7465  SCIPfreeRowprep(scip, &rowprep);
7466  }
7467 
7468  SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7469  }
7470 
7471  return SCIP_OKAY;
7472 }
7473 
7474 /** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7475  *
7476  * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7477  */
7478 static
7480  SCIP* scip, /**< SCIP data structure */
7481  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7482  SCIP_CONS* cons, /**< nonlinear constraint */
7483  SCIP_EXPR* expr, /**< expression */
7484  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7485  SCIP_Longint soltag, /**< tag of solution */
7486  SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7487  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7488  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7489  )
7490 {
7491  SCIP_CONSHDLRDATA* conshdlrdata;
7492  SCIP_EXPR_OWNERDATA* ownerdata;
7493  SCIP_Real origviol;
7494  SCIP_Bool underestimate;
7495  SCIP_Bool overestimate;
7496  SCIP_Real auxviol;
7497  SCIP_Bool auxunderestimate;
7498  SCIP_Bool auxoverestimate;
7499  SCIP_RESULT hdlrresult;
7500  int e;
7501 
7502  assert(scip != NULL);
7503  assert(expr != NULL);
7504  assert(result != NULL);
7505 
7506  ownerdata = SCIPexprGetOwnerData(expr);
7507  assert(ownerdata != NULL);
7508  assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7509 
7510  *result = SCIP_DIDNOTFIND;
7511 
7512  /* make sure that this expression has been evaluated */
7513  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7514 
7515  /* decide whether under- or overestimate is required and get amount of violation */
7516  origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7517 
7518  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7519  assert(conshdlrdata != NULL);
7520 
7521  /* no sufficient violation w.r.t. the original variables -> skip expression */
7522  if( !overestimate && !underestimate )
7523  {
7524  return SCIP_OKAY;
7525  }
7526 
7527  /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7528  for( e = 0; e < ownerdata->nenfos; ++e )
7529  {
7530  SCIP_NLHDLR* nlhdlr;
7531 
7532  /* skip nlhdlr that do not want to participate in any separation */
7533  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7534  continue;
7535 
7536  nlhdlr = ownerdata->enfos[e]->nlhdlr;
7537  assert(nlhdlr != NULL);
7538 
7539  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7540  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7541  ENFOLOG(
7542  SCIPinfoMessage(scip, enfologfile, " expr ");
7543  SCIPprintExpr(scip, expr, enfologfile);
7544  SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7545  "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7546  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7547  )
7548 
7549  /* TODO if expr is root of constraint (consdata->expr == expr),
7550  * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7551  * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7552  * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7553  * so we should enforce in these auxiliaries first
7554  * if changing this here, we must also adapt analyzeViolation()
7555  */
7556 
7557  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7558  assert(auxviol >= 0.0);
7559 
7560  /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7561  if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7562  {
7563  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7564  "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7565  SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7566 
7567  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7568  continue;
7569  }
7570 
7571  /* 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 */
7572  if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7573  {
7574  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7575  "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7576  underestimate, overestimate); )
7577 
7578  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7579  continue;
7580  }
7581 
7582  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7583  "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7584  auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7585 
7586  /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7587  * wants to be called for separation on this side, then call separation of nlhdlr
7588  */
7589  if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7590  {
7591  /* call the separation or estimation callback of the nonlinear handler for overestimation */
7592  hdlrresult = SCIP_DIDNOTFIND;
7593  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7594  ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7595 
7596  if( hdlrresult == SCIP_CUTOFF )
7597  {
7598  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7599  *result = SCIP_CUTOFF;
7600  ownerdata->lastenforced = conshdlrdata->enforound;
7601  break;
7602  }
7603 
7604  if( hdlrresult == SCIP_SEPARATED )
7605  {
7606  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7607  *result = SCIP_SEPARATED;
7608  ownerdata->lastenforced = conshdlrdata->enforound;
7609  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7610  break;
7611  }
7612 
7613  if( hdlrresult == SCIP_REDUCEDDOM )
7614  {
7615  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7616  *result = SCIP_REDUCEDDOM;
7617  ownerdata->lastenforced = conshdlrdata->enforound;
7618  /* TODO or should we always just stop here? */
7619  }
7620 
7621  if( hdlrresult == SCIP_BRANCHED )
7622  {
7623  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7624  assert(inenforcement);
7625 
7626  /* separation and domain reduction takes precedence over branching */
7627  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7628  if( *result == SCIP_DIDNOTFIND )
7629  *result = SCIP_BRANCHED;
7630  ownerdata->lastenforced = conshdlrdata->enforound;
7631  }
7632  }
7633 
7634  /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7635  * wants to be called for separation on this side, then call separation of nlhdlr
7636  */
7637  if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7638  {
7639  /* call the separation or estimation callback of the nonlinear handler for underestimation */
7640  hdlrresult = SCIP_DIDNOTFIND;
7641  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7642  ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7643 
7644  if( hdlrresult == SCIP_CUTOFF )
7645  {
7646  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7647  *result = SCIP_CUTOFF;
7648  ownerdata->lastenforced = conshdlrdata->enforound;
7649  break;
7650  }
7651 
7652  if( hdlrresult == SCIP_SEPARATED )
7653  {
7654  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7655  *result = SCIP_SEPARATED;
7656  ownerdata->lastenforced = conshdlrdata->enforound;
7657  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7658  break;
7659  }
7660 
7661  if( hdlrresult == SCIP_REDUCEDDOM )
7662  {
7663  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7664  *result = SCIP_REDUCEDDOM;
7665  ownerdata->lastenforced = conshdlrdata->enforound;
7666  /* TODO or should we always just stop here? */
7667  }
7668 
7669  if( hdlrresult == SCIP_BRANCHED )
7670  {
7671  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7672  assert(inenforcement);
7673 
7674  /* separation takes precedence over branching */
7675  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7676  if( *result == SCIP_DIDNOTFIND )
7677  *result = SCIP_BRANCHED;
7678  ownerdata->lastenforced = conshdlrdata->enforound;
7679  }
7680  }
7681  }
7682 
7683  return SCIP_OKAY;
7684 }
7685 
7686 /** helper function to enforce a single constraint */
7687 static
7689  SCIP* scip, /**< SCIP data structure */
7690  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7691  SCIP_CONS* cons, /**< constraint to process */
7692  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7693  SCIP_Longint soltag, /**< tag of solution */
7694  SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7695  SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7696  SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7697  SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7698  SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7699  )
7700 {
7701  SCIP_CONSDATA* consdata;
7702  SCIP_CONSHDLRDATA* conshdlrdata;
7703  SCIP_EXPR* expr;
7704 
7705  assert(conshdlr != NULL);
7706  assert(cons != NULL);
7707  assert(it != NULL);
7708  assert(result != NULL);
7709  assert(success != NULL);
7710 
7711  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7712  assert(conshdlrdata != NULL);
7713 
7714  consdata = SCIPconsGetData(cons);
7715  assert(consdata != NULL);
7716  assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7717 
7718  *success = FALSE;
7719 
7720  if( inenforcement && !consdata->ispropagated )
7721  {
7722  /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7723  * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7724  * (TODO: nlhdlr tells us now whether they do and so we could skip).
7725  * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7726  * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7727  * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7728  * confuse the stalling check for how long to do separation).
7729  */
7730  SCIP_Bool infeasible;
7731  int ntightenings;
7732 
7733  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7734  if( infeasible )
7735  {
7736  *result = SCIP_CUTOFF;
7737  return SCIP_OKAY;
7738  }
7739  /* if we tightened an auxvar bound, we better communicate that */
7740  if( ntightenings > 0 )
7741  *result = SCIP_REDUCEDDOM;
7742  }
7743 
7744  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7745  {
7746  SCIP_EXPR_OWNERDATA* ownerdata;
7747  SCIP_RESULT resultexpr;
7748 
7749  ownerdata = SCIPexprGetOwnerData(expr);
7750  assert(ownerdata != NULL);
7751 
7752  /* we can only enforce if there is an auxvar to compare with */
7753  if( ownerdata->auxvar == NULL )
7754  continue;
7755 
7756  assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7757  if( ownerdata->lastenforced == conshdlrdata->enforound )
7758  {
7759  ENFOLOG(
7760  SCIPinfoMessage(scip, enfologfile, " skip expr ");
7761  SCIPprintExpr(scip, expr, enfologfile);
7762  SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7763  )
7764  *success = TRUE;
7765  continue;
7766  }
7767 
7768  SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7769 
7770  /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7771  assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7772  if( ownerdata->lastenforced == conshdlrdata->enforound )
7773  *success = TRUE;
7774 
7775  if( resultexpr == SCIP_CUTOFF )
7776  {
7777  *result = SCIP_CUTOFF;
7778  break;
7779  }
7780 
7781  if( resultexpr == SCIP_SEPARATED )
7782  *result = SCIP_SEPARATED;
7783 
7784  if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7785  *result = SCIP_REDUCEDDOM;
7786 
7787  if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7788  *result = SCIP_BRANCHED;
7789  }
7790 
7791  return SCIP_OKAY;
7792 }
7793 
7794 /** try to separate violated constraints and, if in enforcement, register branching scores
7795  *
7796  * Sets result to
7797  * - SCIP_DIDNOTFIND, if nothing of the below has been done
7798  * - SCIP_CUTOFF, if node can be cutoff,
7799  * - SCIP_SEPARATED, if a cut has been added,
7800  * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7801  * - SCIP_BRANCHED, if branching has been done,
7802  * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7803  * - SCIP_INFEASIBLE, if external branching candidates were registered
7804  */
7805 static
7807  SCIP* scip, /**< SCIP data structure */
7808  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7809  SCIP_CONS** conss, /**< constraints to process */
7810  int nconss, /**< number of constraints */
7811  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7812  SCIP_Longint soltag, /**< tag of solution */
7813  SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7814  SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7815  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7816  )
7817 {
7818  SCIP_CONSHDLRDATA* conshdlrdata;
7819  SCIP_EXPRITER* it;
7820  SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7821  int c;
7822 
7823  assert(conshdlr != NULL);
7824  assert(conss != NULL || nconss == 0);
7825  assert(result != NULL);
7826 
7827  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7828  assert(conshdlrdata != NULL);
7829 
7830  /* increase tag to tell whether branching scores in expression belong to this sweep
7831  * and which expressions have already been enforced in this sweep
7832  * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7833  */
7834  ++(conshdlrdata->enforound);
7835 
7836  *result = SCIP_DIDNOTFIND;
7837 
7838  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7840 
7841  for( c = 0; c < nconss; ++c )
7842  {
7843  assert(conss != NULL && conss[c] != NULL);
7844 
7845  /* skip constraints that are not enabled or deleted */
7846  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7847  continue;
7848  assert(SCIPconsIsActive(conss[c]));
7849 
7850  /* skip constraints that have separation disabled if we are only in separation */
7851  if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7852  continue;
7853 
7854  /* skip non-violated constraints */
7855  if( !isConsViolated(scip, conss[c]) )
7856  continue;
7857 
7858  ENFOLOG(
7859  {
7860  SCIP_CONSDATA* consdata;
7861  int i;
7862  consdata = SCIPconsGetData(conss[c]);
7863  assert(consdata != NULL);
7864  SCIPinfoMessage(scip, enfologfile, " constraint ");
7865  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7866  SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7867  for( i = 0; i < consdata->nvarexprs; ++i )
7868  {
7869  SCIP_VAR* var;
7870  var = SCIPgetVarExprVar(consdata->varexprs[i]);
7871  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7872  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7873  }
7874  })
7875 
7876  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, result, &consenforced) );
7877 
7878  if( *result == SCIP_CUTOFF )
7879  break;
7880 
7881  if( !consenforced && inenforcement )
7882  {
7883  SCIP_Real viol;
7884 
7885  SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7886  if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7887  {
7888  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7889  "cuts allowed\n", SCIPconsGetName(conss[c])); )
7890 
7891  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, result, &consenforced) );
7892 
7893  if( consenforced )
7894  ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7895 
7896  if( *result == SCIP_CUTOFF )
7897  break;
7898  }
7899  }
7900  }
7901 
7902  SCIPfreeExpriter(&it);
7903 
7904  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7905 
7906  /* if having branching scores, then propagate them from expressions with children to variable expressions */
7907  if( *result == SCIP_BRANCHED )
7908  {
7909  /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7910  * branching
7911  */
7912  SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7913 
7914  /* branching should either have branched: result == SCIP_BRANCHED,
7915  * or fixed a variable: result == SCIP_REDUCEDDOM,
7916  * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7917  * or have not done anything: result == SCIP_DIDNOTFIND
7918  */
7919  assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7920  }
7921 
7922  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7923 
7924  return SCIP_OKAY;
7925 }
7926 
7927 /** collect (and print (if debugging enfo)) information on violation in expressions
7928  *
7929  * assumes that constraint violations have been computed
7930  */
7931 static
7933  SCIP* scip, /**< SCIP data structure */
7934  SCIP_CONS** conss, /**< constraints */
7935  int nconss, /**< number of constraints */
7936  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7937  SCIP_Longint soltag, /**< tag of solution */
7938  SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
7939  SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
7940  SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
7941  SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7942  SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
7943  )
7944 {
7945  SCIP_CONSDATA* consdata;
7946  SCIP_EXPRITER* it;
7947  SCIP_EXPR* expr;
7948  SCIP_Real v;
7949  int c;
7950 
7951  assert(conss != NULL || nconss == 0);
7952  assert(maxabsconsviol != NULL);
7953  assert(maxrelconsviol != NULL);
7954  assert(maxauxviol != NULL);
7955  assert(maxvarboundviol != NULL);
7956 
7957  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7959 
7960  *maxabsconsviol = 0.0;
7961  *maxrelconsviol = 0.0;
7962  *minauxviol = SCIPinfinity(scip);
7963  *maxauxviol = 0.0;
7964  *maxvarboundviol = 0.0;
7965 
7966  for( c = 0; c < nconss; ++c )
7967  {
7968  assert(conss != NULL && conss[c] != NULL);
7969 
7970  consdata = SCIPconsGetData(conss[c]);
7971  assert(consdata != NULL);
7972 
7973  /* skip constraints that are not enabled, deleted, or have separation disabled */
7974  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7975  continue;
7976  assert(SCIPconsIsActive(conss[c]));
7977 
7978  v = getConsAbsViolation(conss[c]);
7979  *maxabsconsviol = MAX(*maxabsconsviol, v);
7980 
7981  /* skip non-violated constraints */
7982  if( !isConsViolated(scip, conss[c]) )
7983  continue;
7984 
7985  SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
7986  *maxrelconsviol = MAX(*maxrelconsviol, v);
7987 
7988  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7989  {
7990  SCIP_EXPR_OWNERDATA* ownerdata;
7991  SCIP_Real auxvarvalue;
7992  SCIP_Real auxvarlb;
7993  SCIP_Real auxvarub;
7994  SCIP_Bool violunder;
7995  SCIP_Bool violover;
7996  SCIP_Real origviol;
7997  SCIP_Real auxviol;
7998  int e;
7999 
8000  ownerdata = SCIPexprGetOwnerData(expr);
8001  assert(ownerdata != NULL);
8002 
8003  if( ownerdata->auxvar == NULL )
8004  {
8005  /* check violation of variable bounds of original variable */
8006  if( SCIPisExprVar(scip, expr) )
8007  {
8008  SCIP_VAR* var;
8009  var = SCIPgetVarExprVar(expr);
8010  auxvarvalue = SCIPgetSolVal(scip, sol, var);
8011  auxvarlb = SCIPvarGetLbLocal(var);
8012  auxvarub = SCIPvarGetUbLocal(var);
8013 
8014  origviol = 0.0;
8015  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8016  origviol = auxvarlb - auxvarvalue;
8017  else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8018  origviol = auxvarvalue - auxvarub;
8019  if( origviol <= 0.0 )
8020  continue;
8021 
8022  *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8023 
8024  ENFOLOG(
8025  SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8026  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8027  SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8028  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8029  SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8030  SCIPinfoMessage(scip, enfologfile, "\n");
8031  )
8032  }
8033 
8034  continue;
8035  }
8036 
8037  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8038  auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8039  auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8040 
8041  /* check violation of variable bounds of auxiliary variable */
8042  if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8043  *maxvarboundviol = auxvarlb - auxvarvalue;
8044  else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8045  *maxvarboundviol = auxvarvalue - auxvarub;
8046 
8047  origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8048 
8049  ENFOLOG(
8050  if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8051  {
8052  SCIPinfoMessage(scip, enfologfile, "expr ");
8053  SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8054  SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8055 
8056  SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8057  if( origviol > 0.0 )
8058  SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8059  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8060  SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8061  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8062  SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8063  SCIPinfoMessage(scip, enfologfile, "\n");
8064  }
8065  )
8066 
8067  /* no violation w.r.t. the original variables -> skip expression */
8068  if( origviol == 0.0 )
8069  continue;
8070 
8071  /* compute aux-violation for each nonlinear handlers */
8072  for( e = 0; e < ownerdata->nenfos; ++e )
8073  {
8074  SCIP_NLHDLR* nlhdlr;
8075 
8076  /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8077  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8078  continue;
8079 
8080  nlhdlr = ownerdata->enfos[e]->nlhdlr;
8081  assert(nlhdlr != NULL);
8082 
8083  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8084  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8085 
8086  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8087 
8088  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8089 
8090  if( auxviol > 0.0 )
8091  {
8092  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8093  *maxauxviol = MAX(*maxauxviol, auxviol);
8094  *minauxviol = MIN(*minauxviol, auxviol);
8095  }
8096  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8097  }
8098  }
8099  }
8100 
8101  SCIPfreeExpriter(&it);
8102 
8103  return SCIP_OKAY;
8104 } /*lint !e715*/
8105 
8106 /** enforcement of constraints called by enfolp and enforelax */
8107 static
8109  SCIP* scip, /**< SCIP data structure */
8110  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8111  SCIP_CONS** conss, /**< constraints to process */
8112  int nconss, /**< number of constraints */
8113  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8114  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8115  )
8116 {
8117  SCIP_CONSHDLRDATA* conshdlrdata;
8118  SCIP_Real maxabsconsviol;
8119  SCIP_Real maxrelconsviol;
8120  SCIP_Real minauxviol;
8121  SCIP_Real maxauxviol;
8122  SCIP_Real maxvarboundviol;
8123  SCIP_Longint soltag;
8124  int nnotify;
8125  int c;
8126 
8127  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8128  assert(conshdlr != NULL);
8129 
8130  soltag = SCIPgetExprNewSoltag(scip);
8131 
8132  *result = SCIP_FEASIBLE;
8133  for( c = 0; c < nconss; ++c )
8134  {
8135  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8136 
8137  if( isConsViolated(scip, conss[c]) )
8138  *result = SCIP_INFEASIBLE;
8139  }
8140 
8141  if( *result == SCIP_FEASIBLE )
8142  {
8143  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8145  return SCIP_OKAY;
8146  }
8147 
8148  SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8149  &minauxviol, &maxauxviol, &maxvarboundviol) );
8150 
8151  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8152  "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8153  SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8154  maxvarboundviol, SCIPgetLPFeastol(scip)); )
8155 
8156  assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8157 
8158  /* try to propagate */
8159  if( conshdlrdata->propinenforce )
8160  {
8161  SCIP_RESULT propresult;
8162  int nchgbds = 0;
8163 
8164  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8165 
8166  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8167  {
8168  *result = propresult;
8169  return SCIP_OKAY;
8170  }
8171  }
8172 
8173  /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8174  * all violated expr/auxvar in violated constraints)
8175  */
8176  if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8177  sol == NULL )
8178  {
8179  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8180  ++conshdlrdata->ntightenlp;
8181 
8182  *result = SCIP_SOLVELP;
8183 
8184  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8185  "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8186 
8187  return SCIP_OKAY;
8188  }
8189 
8190  /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8191  * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8192  */
8193  if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8194  {
8195  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8196  ++conshdlrdata->ntightenlp;
8197 
8198  *result = SCIP_SOLVELP;
8199 
8200  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8201 
8202  return SCIP_OKAY;
8203  }
8204 
8205  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8206 
8207  if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8208  *result == SCIP_INFEASIBLE )
8209  return SCIP_OKAY;
8210 
8211  assert(*result == SCIP_DIDNOTFIND);
8212 
8213  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8214  "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8215 
8216  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8217  {
8218  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8219  ++conshdlrdata->ntightenlp;
8220 
8221  *result = SCIP_SOLVELP;
8222 
8223  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8224  "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8225 
8226  return SCIP_OKAY;
8227  }
8228 
8229  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8230  SCIPgetLPFeastol(scip)) && sol == NULL )
8231  {
8232  /* try whether tighten the LP feasibility tolerance could help
8233  * maybe it is just some cut that hasn't been taken into account sufficiently
8234  * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8235  * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8236  * until the LP feastol reaches epsilon
8237  * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8238  * when maxauxviol is above LP feastol)
8239  */
8240  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8241  ++conshdlrdata->ndesperatetightenlp;
8242 
8243  *result = SCIP_SOLVELP;
8244 
8245  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8246 
8247  return SCIP_OKAY;
8248  }
8249 
8250  /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8251  if( !conshdlrdata->propinenforce )
8252  {
8253  SCIP_RESULT propresult;
8254  int nchgbds = 0;
8255 
8256  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8257 
8258  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8259  {
8260  *result = propresult;
8261  return SCIP_OKAY;
8262  }
8263  }
8264 
8265  /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8266  * now look if we find any unfixed variable that we could still branch on
8267  */
8268  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8269 
8270  if( nnotify > 0 )
8271  {
8272  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8273  ++conshdlrdata->ndesperatebranch;
8274 
8275  *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8276 
8277  return SCIP_OKAY;
8278  }
8279 
8280  /* if everything is fixed in violated constraints, then let's cut off the node
8281  * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8282  * result may not be conclusive (when constraint violations are small)
8283  * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8284  * sufficiently (see st_e40)
8285  * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8286  * not "desperate", but a pretty obvious thing to do
8287  */
8288  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8289  *result = SCIP_CUTOFF;
8290 
8291  /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8292  if( !SCIPisZero(scip, maxvarboundviol) )
8293  ++conshdlrdata->ndesperatecutoff;
8294 
8295  return SCIP_OKAY;
8296 }
8297 
8298 /** separation for all violated constraints to be used by SEPA callbacks */
8299 static
8301  SCIP* scip, /**< SCIP data structure */
8302  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8303  SCIP_CONS** conss, /**< constraints to process */
8304  int nconss, /**< number of constraints */
8305  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8306  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8307  )
8308 {
8309  SCIP_Longint soltag;
8310  SCIP_Bool haveviol = FALSE;
8311  int c;
8312 
8313  *result = SCIP_DIDNOTFIND;
8314 
8315  soltag = SCIPgetExprNewSoltag(scip);
8316 
8317  /* compute violations */
8318  for( c = 0; c < nconss; ++c )
8319  {
8320  assert(conss[c] != NULL);
8321 
8322  /* skip constraints that are not enabled, deleted, or have separation disabled */
8323  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8324  continue;
8325  assert(SCIPconsIsActive(conss[c]));
8326 
8327  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8328 
8329  if( isConsViolated(scip, conss[c]) )
8330  haveviol = TRUE;
8331  }
8332 
8333  /* if none of our constraints are violated, don't attempt separation */
8334  if( !haveviol )
8335  {
8336  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8337  return SCIP_OKAY;
8338  }
8339 
8340  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8341 
8342  /* call separation */
8343  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8344 
8345  return SCIP_OKAY;
8346 }
8347 
8348 /** hash key retrieval function for bilinear term entries */
8349 static
8350 SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8351 { /*lint --e{715}*/
8352  SCIP_CONSHDLRDATA* conshdlrdata;
8353  int idx;
8354 
8355  conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8356  assert(conshdlrdata != NULL);
8357 
8358  idx = ((int)(size_t)elem) - 1;
8359  assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8360 
8361  return (void*)&conshdlrdata->bilinterms[idx];
8362 }
8363 
8364 /** returns TRUE iff the bilinear term entries are equal */
8365 static
8366 SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8367 { /*lint --e{715}*/
8370 
8371  /* get corresponding entries */
8372  entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8373  entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8374  assert(entry1->x != NULL && entry1->y != NULL);
8375  assert(entry2->x != NULL && entry2->y != NULL);
8376  assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8377  assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8378 
8379  return entry1->x == entry2->x && entry1->y == entry2->y;
8380 }
8381 
8382 /** returns the hash value of the key */
8383 static
8384 SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8385 { /*lint --e{715}*/
8387 
8389  assert(entry->x != NULL && entry->y != NULL);
8390  assert(SCIPvarCompare(entry->x, entry->y) < 1);
8391 
8392  return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8393 }
8394 
8395 /** compare two auxiliary expressions
8396  *
8397  * Compares auxiliary variables, followed by coefficients, and then constants.
8398  */
8399 static
8400 SCIP_DECL_SORTPTRCOMP(auxexprComp)
8404  int compvars;
8405  int i;
8406 
8407  /* compare the auxiliary variables */
8408  compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8409 
8410  if( compvars != 0 )
8411  return compvars;
8412 
8413  /* compare the coefficients and constants */
8414  for( i = 0; i < 3; ++i )
8415  {
8416  if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8417  return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8418  }
8419 
8420  return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8421 }
8422 
8423 /* add an auxiliary expression to a bilinear term */
8424 static
8426  SCIP* scip, /**< SCIP data structure */
8427  SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8428  SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8429  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8430  SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8431  )
8432 {
8433  SCIP_Bool found;
8434  int pos;
8435  int i;
8436 
8437  *added = FALSE;
8438 
8439  /* check if auxexpr has already been added to term */
8440  if( term->nauxexprs == 0 )
8441  {
8442  found = FALSE;
8443  pos = 0;
8444  }
8445  else
8446  {
8447  found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8448  }
8449 
8450  if( !found )
8451  {
8452  if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8453  return SCIP_OKAY;
8454 
8455  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8456  assert(term->auxexprssize >= term->nauxexprs + 1);
8457 
8458  /* insert expression at the correct position */
8459  for( i = term->nauxexprs; i > pos; --i )
8460  {
8461  term->aux.exprs[i] = term->aux.exprs[i-1];
8462  }
8463  term->aux.exprs[pos] = auxexpr;
8464  ++(term->nauxexprs);
8465  *added = TRUE;
8466  }
8467  else
8468  {
8469  term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8470  term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8471  }
8472 
8473  return SCIP_OKAY;
8474 }
8475 
8476 /** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8477 static
8479  SCIP* scip, /**< SCIP data structure */
8480  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8481  SCIP_CONS** conss, /**< nonlinear constraints */
8482  int nconss /**< total number of nonlinear constraints */
8483  )
8484 {
8485  SCIP_CONSHDLRDATA* conshdlrdata;
8486  SCIP_EXPRITER* it;
8487  int c;
8488 
8489  assert(conss != NULL || nconss == 0);
8490 
8491  if( nconss == 0 )
8492  return SCIP_OKAY;
8493 
8494  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8495  assert(conshdlrdata != NULL);
8496 
8497  /* check whether the bilinear terms have been stored already */
8498  if( conshdlrdata->bilinterms != NULL )
8499  return SCIP_OKAY;
8500 
8501  /* create and initialize iterator */
8502  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8505 
8506  /* iterate through all constraints */
8507  for( c = 0; c < nconss; ++c )
8508  {
8509  SCIP_CONSDATA* consdata;
8510  SCIP_EXPR* expr;
8511 
8512  assert(conss != NULL && conss[c] != NULL);
8513  consdata = SCIPconsGetData(conss[c]);
8514  assert(consdata != NULL);
8515 
8516  /* iterate through all expressions */
8517  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8518  {
8519  SCIP_EXPR** children = SCIPexprGetChildren(expr);
8520  SCIP_VAR* x = NULL;
8521  SCIP_VAR* y = NULL;
8522 
8523  /* check whether the expression is of the form f(..)^2 */
8524  if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8525  {
8526  x = SCIPgetExprAuxVarNonlinear(children[0]);
8527  y = x;
8528  }
8529  /* check whether the expression is of the form f(..) * g(..) */
8530  else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8531  {
8532  x = SCIPgetExprAuxVarNonlinear(children[0]);
8533  y = SCIPgetExprAuxVarNonlinear(children[1]);
8534  }
8535 
8536  /* add variables to the hash table */
8537  if( x != NULL && y != NULL )
8538  {
8541  }
8542  }
8543  }
8544 
8545  /* release iterator */
8546  SCIPfreeExpriter(&it);
8547 
8548  return SCIP_OKAY;
8549 }
8550 
8551 /** store x, y and the locks in a new bilinear term */
8552 static
8554  SCIP* scip, /**< SCIP data structure */
8555  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8556  SCIP_VAR* x, /**< the first variable */
8557  SCIP_VAR* y, /**< the second variable */
8558  int nlockspos, /**< number of positive locks of the bilinear term */
8559  int nlocksneg, /**< number of negative locks of the bilinear term */
8560  int* idx, /**< pointer to store the position of the term in bilinterms array */
8561  SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8562  )
8563 {
8564  SCIP_CONSHDLRDATA* conshdlrdata;
8566 
8567  assert(conshdlr != NULL);
8568  assert(x != NULL);
8569  assert(y != NULL);
8570  assert(nlockspos >= 0);
8571  assert(nlocksneg >= 0);
8572 
8573  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8574  assert(conshdlrdata != NULL);
8575 
8576  /* ensure that x.index <= y.index */
8577  if( SCIPvarCompare(x, y) == 1 )
8578  {
8579  SCIPswapPointers((void**)&x, (void**)&y);
8580  }
8581  assert(SCIPvarCompare(x, y) < 1);
8582 
8583  *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8584 
8585  /* update or create the term */
8586  if( *idx >= 0 )
8587  { /* the term has already been added */
8588  assert(conshdlrdata->bilinterms[*idx].x == x);
8589  assert(conshdlrdata->bilinterms[*idx].y == y);
8590 
8591  /* get term and add locks */
8592  term = &conshdlrdata->bilinterms[*idx];
8593  assert(existing <= term->existing); /* implicit terms are added after existing ones */
8594  term->nlockspos += nlockspos;
8595  term->nlocksneg += nlocksneg;
8596  }
8597  else
8598  { /* this is the first time we encounter this product */
8599  /* ensure size of bilinterms array */
8600  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8601 
8602  *idx = conshdlrdata->nbilinterms;
8603 
8604  /* get term and set values in the created bilinear term */
8605  term = &conshdlrdata->bilinterms[*idx];
8606  assert(term != NULL);
8607  term->x = x;
8608  term->y = y;
8609  term->nauxexprs = 0;
8610  term->auxexprssize = 0;
8611  term->nlockspos = nlockspos;
8612  term->nlocksneg = nlocksneg;
8613  term->existing = existing;
8614  if( existing )
8615  term->aux.var = NULL;
8616  else
8617  term->aux.exprs = NULL;
8618 
8619  /* increase the total number of bilinear terms */
8620  ++(conshdlrdata->nbilinterms);
8621 
8622  /* save to the hashtable */
8623  if( conshdlrdata->bilinhashtable == NULL )
8624  {
8625  SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8626  bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8627  (void*)conshdlrdata) );
8628  }
8629  assert(conshdlrdata->bilinhashtable != NULL);
8630 
8631  /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8632  * because zero can not be inserted into hash table
8633  */
8634  SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8635 
8636  /* capture product variables */
8637  SCIP_CALL( SCIPcaptureVar(scip, x) );
8638  SCIP_CALL( SCIPcaptureVar(scip, y) );
8639  }
8640 
8641  return SCIP_OKAY;
8642 }
8643 
8644 /** frees array of bilinear terms and hash table */
8645 static
8647  SCIP* scip, /**< SCIP data structure */
8648  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8649  )
8650 {
8651  int i;
8652  int j;
8653 
8654  assert(conshdlrdata != NULL);
8655 
8656  /* check whether bilinear terms have been stored */
8657  if( conshdlrdata->bilinterms == NULL )
8658  {
8659  assert(conshdlrdata->bilinterms == NULL);
8660  assert(conshdlrdata->nbilinterms == 0);
8661  assert(conshdlrdata->bilintermssize == 0);
8662 
8663  return SCIP_OKAY;
8664  }
8665 
8666  /* release variables */
8667  for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8668  {
8669  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8670  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8671 
8672  for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8673  {
8674  if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8675  {
8676  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8677  }
8678  SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8679  }
8680 
8681  if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8682  {
8683  SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8684  continue;
8685  }
8686 
8687  /* the rest is for simple terms with a single auxvar */
8688 
8689  /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8690  if( conshdlrdata->bilinterms[i].aux.var != NULL )
8691  {
8692  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8693  }
8694  }
8695 
8696  /* free hash table */
8697  if( conshdlrdata->bilinhashtable != NULL )
8698  {
8699  SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8700  }
8701 
8702  /* free bilinterms array; reset counters */
8703  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8704  conshdlrdata->nbilinterms = 0;
8705  conshdlrdata->bilintermssize = 0;
8706 
8707  return SCIP_OKAY;
8708 }
8709 
8710 /*
8711  * vertex polyhedral separation
8712  */
8713 
8714 /** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8715 static
8717  SCIP* scip, /**< SCIP data structure */
8718  int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
8719  SCIP_LPI** lp /**< pointer to store created LP */
8720  )
8721 {
8722  SCIP_Real* obj;
8723  SCIP_Real* lb;
8724  SCIP_Real* ub;
8725  SCIP_Real* val;
8726  int* beg;
8727  int* ind;
8728  unsigned int nnonz;
8729  unsigned int ncols;
8730  unsigned int nrows;
8731  unsigned int i;
8732  unsigned int k;
8733 
8734  assert(scip != NULL);
8735  assert(lp != NULL);
8736  assert(nvars > 0);
8737  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8738 
8739  SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8740 
8741  /* create lpi to store the LP */
8742  SCIP_CALL( SCIPlpiCreate(lp, SCIPgetMessagehdlr(scip), "facet finding LP", SCIP_OBJSEN_MINIMIZE) );
8743 
8744  nrows = (unsigned int)nvars + 1;
8745  ncols = POWEROFTWO((unsigned int)nvars);
8746  nnonz = (ncols * (nrows + 1)) / 2;
8747 
8748  /* allocate necessary memory; set obj, lb, and ub to zero */
8749  SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
8750  SCIP_CALL( SCIPallocClearBufferArray(scip, &lb, ncols) );
8751  SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8752  SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8753  SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8754  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8755 
8756  /* calculate nonzero entries in the LP */
8757  for( i = 0, k = 0; i < ncols; ++i )
8758  {
8759  int row;
8760  unsigned int a;
8761 
8762  /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8763  ub[i] = SCIPlpiInfinity(*lp);
8764 
8765  SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8766  beg[i] = (int)k;
8767  row = 0;
8768 
8769  /* iterate through the bit representation of i */
8770  a = 1;
8771  while( a <= i )
8772  {
8773  if( (a & i) != 0 )
8774  {
8775  val[k] = 1.0;
8776  ind[k] = row;
8777 
8778  SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
8779 
8780  ++k;
8781  }
8782 
8783  a <<= 1;
8784  ++row;
8785  assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8786  assert(POWEROFTWO(row) == a);
8787  }
8788 
8789  /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8790  val[k] = 1.0;
8791  ind[k] = (int)nrows - 1;
8792  ++k;
8793  SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
8794  }
8795  assert(k == nnonz);
8796 
8797  /* load all data into LP interface
8798  * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8799  */
8800  assert(nrows <= ncols);
8802  (int)ncols, obj, lb, ub, NULL,
8803  (int)nrows, lb, lb, NULL,
8804  (int)nnonz, beg, ind, val) );
8805 
8806  /* for the last row, we can set the rhs to 1.0 already */
8807  ind[0] = (int)nrows - 1;
8808  val[0] = 1.0;
8809  SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8810 
8811  /* free allocated memory */
8812  SCIPfreeBufferArray(scip, &ind);
8813  SCIPfreeBufferArray(scip, &val);
8814  SCIPfreeBufferArray(scip, &beg);
8815  SCIPfreeBufferArray(scip, &ub);
8816  SCIPfreeBufferArray(scip, &lb);
8817  SCIPfreeBufferArray(scip, &obj);
8818 
8819  return SCIP_OKAY;
8820 }
8821 
8822 /** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8823  * \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
8824  * set of vertices of the domain
8825  */
8826 static
8828  SCIP* scip, /**< SCIP data structure */
8829  SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
8830  SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8831  SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
8832  int nallvars, /**< number of all variables */
8833  int nvars, /**< number of unfixed variables */
8834  int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
8835  SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
8836  SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
8837  )
8838 {
8839  SCIP_Real maxerror;
8840  SCIP_Real facetval;
8841  SCIP_Real funval;
8842  SCIP_Real error;
8843  unsigned int i;
8844  unsigned int ncorners;
8845  unsigned int prev;
8846 
8847  assert(scip != NULL);
8848  assert(funvals != NULL);
8849  assert(box != NULL);
8850  assert(nonfixedpos != NULL);
8851  assert(facetcoefs != NULL);
8852 
8853  ncorners = POWEROFTWO(nvars);
8854  maxerror = 0.0;
8855 
8856  /* check the origin (all variables at lower bound) */
8857  facetval = facetconstant;
8858  for( i = 0; i < (unsigned int) nallvars; ++i )
8859  facetval += facetcoefs[i] * box[2*i];
8860 
8861  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8862  funval = funvals[0];
8863  if( overestimate )
8864  error = funval - facetval;
8865  else
8866  error = facetval - funval;
8867 
8868  /* update maximum error */
8869  maxerror = MAX(error, maxerror);
8870 
8871  prev = 0;
8872  for( i = 1; i < ncorners; ++i )
8873  {
8874  unsigned int gray;
8875  unsigned int diff;
8876  unsigned int pos;
8877  int origpos;
8878 
8879  gray = i ^ (i >> 1);
8880  diff = gray ^ prev;
8881 
8882  /* compute position of unique 1 of diff */
8883  pos = 0;
8884  while( (diff >>= 1) != 0 )
8885  ++pos;
8886  assert(pos < (unsigned int)nvars);
8887 
8888  origpos = nonfixedpos[pos];
8889 
8890  if( gray > prev )
8891  facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8892  else
8893  facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8894 
8895  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8896  funval = funvals[gray];
8897  if( overestimate )
8898  error = funval - facetval;
8899  else
8900  error = facetval - funval;
8901 
8902  /* update maximum error */
8903  maxerror = MAX(error, maxerror);
8904 
8905  prev = gray;
8906  }
8907 
8908  SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8909 
8910  return maxerror;
8911 }
8912 
8913 /** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
8914 static
8916  SCIP* scip, /**< SCIP data structure */
8917  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8918  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8919  SCIP_Real* xstar, /**< point to be separated */
8920  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8921  int nallvars, /**< half of the length of box */
8922  int* nonfixedpos, /**< indices of nonfixed variables */
8923  SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
8924  int nvars, /**< number of nonfixed variables */
8925  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
8926  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
8927  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8928  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
8929  )
8930 { /*lint --e{715}*/
8931  SCIP_CONSHDLRDATA* conshdlrdata;
8932  SCIP_LPI* lp;
8933  SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8934  int* inds;
8935  int ncols;
8936  int nrows;
8937  int i;
8938  SCIP_Real facetvalue;
8939  SCIP_Real mindomwidth;
8940  SCIP_RETCODE lpsolveretcode;
8941 
8942  assert(scip != NULL);
8943  assert(conshdlr != NULL);
8944  assert(xstar != NULL);
8945  assert(box != NULL);
8946  assert(nonfixedpos != NULL);
8947  assert(funvals != NULL);
8948  assert(nvars >= 0);
8949  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8950  assert(success != NULL);
8951  assert(facetcoefs != NULL);
8952  assert(facetconstant != NULL);
8953 
8954  *success = FALSE;
8955 
8956  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8957  assert(conshdlrdata != NULL);
8958 
8959  if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8960  {
8961  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8962  }
8963 
8964  /* construct an LP for this size, if not having one already */
8965  if( conshdlrdata->vp_lp[nvars] == NULL )
8966  {
8967  SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8968  }
8969  lp = conshdlrdata->vp_lp[nvars];
8970  assert(lp != NULL);
8971 
8972  /* get number of cols and rows of separation lp */
8973  SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8974  SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8975 
8976  /* number of columns should equal the number of corners = 2^nvars */
8977  assert(ncols == (int)POWEROFTWO(nvars));
8978 
8979  /* allocate necessary memory */
8980  SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8981  SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8982 
8983  /*
8984  * set up the described LP on the transformed space
8985  */
8986 
8987  for( i = 0; i < ncols; ++i )
8988  inds[i] = i;
8989 
8990  /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
8991  mindomwidth = 2*SCIPinfinity(scip);
8992  for( i = 0; i < nrows-1; ++i )
8993  {
8994  SCIP_Real solval;
8995  SCIP_Real lb;
8996  SCIP_Real ub;
8997  int varpos;
8998 
8999  assert(i < nvars);
9000 
9001  varpos = nonfixedpos[i];
9002  lb = box[2 * varpos];
9003  ub = box[2 * varpos + 1];
9004  solval = xstar[varpos];
9005 
9006  if( ub - lb < mindomwidth )
9007  mindomwidth = ub - lb;
9008 
9009  /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9010  if( solval <= lb )
9011  aux[i] = 0.0;
9012  else if( solval >= ub )
9013  aux[i] = 1.0;
9014  else
9015  aux[i] = (solval - lb) / (ub - lb);
9016 
9017  /* perturb point to hopefully obtain a facet of the convex envelope */
9018  if( conshdlrdata->vp_maxperturb > 0.0 )
9019  {
9020  assert(conshdlrdata->vp_randnumgen != NULL);
9021 
9022  if( aux[i] == 1.0 )
9023  aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9024  else if( aux[i] == 0.0 )
9025  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9026  else
9027  {
9028  SCIP_Real perturbation;
9029 
9030  perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9031  perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9032  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9033  }
9034  assert(0.0 < aux[i] && aux[i] < 1.0);
9035  }
9036 
9037  SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9038  }
9039 
9040  /* update LP */
9041  SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9042  SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9044 
9045  /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9046  if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9047  {
9048  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9049  }
9050  /* set an iteration limit so we do not run forever */
9051  SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPITLIM, 100*ncols) );
9052  /* 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 */
9054  /* since we work with the dual of the LP, dual feastol determines validity of the facet
9055  * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9056  * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9057  */
9058  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, MIN(SCIPfeastol(scip), MAX(SCIPepsilon(scip), mindomwidth * SCIPfeastol(scip)))) );
9059 
9060 #ifdef SCIP_DEBUG
9062 #endif
9063 
9064  /*
9065  * solve the LP and store the resulting facet for the transformed space
9066  */
9067  if( conshdlrdata->vp_dualsimplex )
9068  {
9069  lpsolveretcode = SCIPlpiSolveDual(lp);
9070  }
9071  else
9072  {
9073  lpsolveretcode = SCIPlpiSolvePrimal(lp);
9074  }
9075  if( lpsolveretcode == SCIP_LPERROR )
9076  {
9077  SCIPdebugMsg(scip, "LP error, aborting.\n");
9078  goto CLEANUP;
9079  }
9080  SCIP_CALL( lpsolveretcode );
9081 
9082  /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9083  if( !SCIPlpiIsDualFeasible(lp) )
9084  {
9085  SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9086  goto CLEANUP;
9087  }
9088 
9089  /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9090  * columns than needed, in particular, \bar \beta is the last dual multiplier
9091  */
9092  SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9093 
9094  for( i = 0; i < nvars; ++i )
9095  facetcoefs[nonfixedpos[i]] = aux[i];
9096  /* last dual multiplier is the constant */
9097  *facetconstant = aux[nrows - 1];
9098 
9099 #ifdef SCIP_DEBUG
9100  SCIPdebugMsg(scip, "facet for the transformed problem: ");
9101  for( i = 0; i < nallvars; ++i )
9102  {
9103  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9104  }
9105  SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9106 #endif
9107 
9108  /*
9109  * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9110  */
9111 
9112  SCIPdebugMsg(scip, "facet in orig. space: ");
9113 
9114  facetvalue = 0.0;
9115  for( i = 0; i < nvars; ++i )
9116  {
9117  SCIP_Real lb;
9118  SCIP_Real ub;
9119  int varpos;
9120 
9121  varpos = nonfixedpos[i];
9122  lb = box[2 * varpos];
9123  ub = box[2 * varpos + 1];
9124  assert(!SCIPisEQ(scip, lb, ub));
9125 
9126  /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9127  facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9128 
9129  /* beta = beta_bar - sum_i alpha_i * lb_i */
9130  *facetconstant -= facetcoefs[varpos] * lb;
9131 
9132  /* evaluate */
9133  facetvalue += facetcoefs[varpos] * xstar[varpos];
9134 
9135  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9136  }
9137  SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9138 
9139  /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9140  facetvalue += *facetconstant;
9141 
9142  SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9143 
9144  /* if overestimate, then we want facetvalue < targetvalue
9145  * if underestimate, then we want facetvalue > targetvalue
9146  * if none holds, give up
9147  * so maybe here we should check against the minimal violation
9148  */
9149  if( overestimate == (facetvalue > targetvalue) )
9150  {
9151  SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9152  goto CLEANUP;
9153  }
9154 
9155  /* if we made it until here, then we have a nice facet */
9156  *success = TRUE;
9157 
9158 CLEANUP:
9159  /* free allocated memory */
9160  SCIPfreeBufferArray(scip, &inds);
9161  SCIPfreeBufferArray(scip, &aux);
9162 
9163  return SCIP_OKAY;
9164 }
9165 
9166 /** computes a facet of the convex or concave envelope of a univariant vertex polyhedral function
9167  *
9168  * In other words, compute the line that passes through two given points.
9169  */
9170 static
9172  SCIP* scip, /**< SCIP data structure */
9173  SCIP_Real left, /**< left coordinate */
9174  SCIP_Real right, /**< right coordinate */
9175  SCIP_Real funleft, /**< value of function in left coordinate */
9176  SCIP_Real funright, /**< value of function in right coordinate */
9177  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9178  SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9179  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9180  )
9181 {
9182  assert(scip != NULL);
9183  assert(SCIPisLE(scip, left, right));
9184  assert(!SCIPisInfinity(scip, -left));
9185  assert(!SCIPisInfinity(scip, right));
9186  assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9187  assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9188  assert(success != NULL);
9189  assert(facetcoef != NULL);
9190  assert(facetconstant != NULL);
9191 
9192  *facetcoef = (funright - funleft) / (right - left);
9193  *facetconstant = funleft - *facetcoef * left;
9194 
9195  *success = TRUE;
9196 
9197  return SCIP_OKAY;
9198 }
9199 
9200 /** given three points, constructs coefficient of equation for hyperplane generated by these three points
9201  *
9202  * Three points a, b, and c are given.
9203  * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9204  * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9205  */
9206 static
9208  SCIP* scip, /**< SCIP data structure */
9209  SCIP_Real a1, /**< first coordinate of a */
9210  SCIP_Real a2, /**< second coordinate of a */
9211  SCIP_Real a3, /**< third coordinate of a */
9212  SCIP_Real b1, /**< first coordinate of b */
9213  SCIP_Real b2, /**< second coordinate of b */
9214  SCIP_Real b3, /**< third coordinate of b */
9215  SCIP_Real c1, /**< first coordinate of c */
9216  SCIP_Real c2, /**< second coordinate of c */
9217  SCIP_Real c3, /**< third coordinate of c */
9218  SCIP_Real* alpha, /**< coefficient of first coordinate */
9219  SCIP_Real* beta, /**< coefficient of second coordinate */
9220  SCIP_Real* gamma_, /**< coefficient of third coordinate */
9221  SCIP_Real* delta /**< constant right-hand side */
9222  )
9223 {
9224  assert(scip != NULL);
9225  assert(alpha != NULL);
9226  assert(beta != NULL);
9227  assert(gamma_ != NULL);
9228  assert(delta != NULL);
9229 
9230  *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9231  *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9232  *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9233  *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9234 
9235  /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9236 
9237  if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9238  SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9239  SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9240  {
9241  SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9242  *delta = 0.0;
9243  *alpha = 0.0;
9244  *beta = 0.0;
9245  *gamma_ = 0.0;
9246  return SCIP_OKAY;
9247  }
9248 
9249  /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9250  if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9251  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9252  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9253  {
9254  SCIP_Real m[9];
9255  SCIP_Real rhs[3];
9256  SCIP_Real x[3];
9257  SCIP_Bool success;
9258 
9259  /*
9260  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));
9261  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));
9262  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));
9263  */
9264 
9265  /* initialize matrix column-wise */
9266  m[0] = a1;
9267  m[1] = b1;
9268  m[2] = c1;
9269  m[3] = a2;
9270  m[4] = b2;
9271  m[5] = c2;
9272  m[6] = a3;
9273  m[7] = b3;
9274  m[8] = c3;
9275 
9276  rhs[0] = 1.0;
9277  rhs[1] = 1.0;
9278  rhs[2] = 1.0;
9279 
9280  SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9281 
9282  /* solve the linear problem */
9283  SCIP_CALL( SCIPsolveLinearEquationsIpopt(3, m, rhs, x, &success) );
9284 
9285  *delta = rhs[0];
9286  *alpha = x[0];
9287  *beta = x[1];
9288  *gamma_ = x[2];
9289 
9290  /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9291  * not add a cut to SCIP and that all assertions are trivially fulfilled
9292  */
9293  if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9294  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9295  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9296  {
9297  SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9298  *delta = 0.0;
9299  *alpha = 0.0;
9300  *beta = 0.0;
9301  *gamma_ = 0.0;
9302  }
9303  }
9304 
9305  if( *gamma_ < 0.0 )
9306  {
9307  *alpha = -*alpha;
9308  *beta = -*beta;
9309  *gamma_ = -*gamma_;
9310  *delta = -*delta;
9311  }
9312 
9313  return SCIP_OKAY;
9314 }
9315 
9316 /** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9317 static
9319  SCIP* scip, /**< SCIP data structure */
9320  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9321  SCIP_Real p1[2], /**< first vertex of box */
9322  SCIP_Real p2[2], /**< second vertex of box */
9323  SCIP_Real p3[2], /**< third vertex of box */
9324  SCIP_Real p4[2], /**< forth vertex of box */
9325  SCIP_Real p1val, /**< value in p1 */
9326  SCIP_Real p2val, /**< value in p2 */
9327  SCIP_Real p3val, /**< value in p3 */
9328  SCIP_Real p4val, /**< value in p4 */
9329  SCIP_Real xstar[2], /**< point to be separated */
9330  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9331  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9332  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9333  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9334  )
9335 {
9336  SCIP_Real alpha, beta, gamma_, delta;
9337  SCIP_Real xstarval, candxstarval = 0.0;
9338  int leaveout;
9339 
9340  assert(scip != NULL);
9341  assert(success != NULL);
9342  assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9343  assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9344  assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9345  assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9346  assert(facetcoefs != NULL);
9347  assert(facetconstant != NULL);
9348 
9349  *success = FALSE;
9350 
9351  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9352  if( !overestimate )
9353  {
9354  p1val = -p1val;
9355  p2val = -p2val;
9356  p3val = -p3val;
9357  p4val = -p4val;
9358  targetvalue = -targetvalue;
9359  }
9360 
9361  SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9362  SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9363  SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9364  SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9365 
9366  /* Compute coefficients alpha, beta, gamma (>0), delta such that
9367  * alpha*x + beta*y + gamma*z = delta
9368  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9369  * the fourth corner point lies below this hyperplane.
9370  * 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.,
9371  * alpha*x + beta*y - delta <= -gamma * f(x,y),
9372  * or, equivalently,
9373  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9374  */
9375  for( leaveout = 1; leaveout <= 4; ++leaveout )
9376  {
9377  switch( leaveout)
9378  {
9379  case 1 :
9380  /* get hyperplane through p2, p3, p4 */
9381  SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9382  &alpha, &beta, &gamma_, &delta) );
9383  /* if not underestimating in p1, then go to next candidate */
9384  if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9385  continue;
9386  break;
9387 
9388  case 2 :
9389  /* get hyperplane through p1, p3, p4 */
9390  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9391  &alpha, &beta, &gamma_, &delta) );
9392  /* if not underestimating in p2, then go to next candidate */
9393  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9394  continue;
9395  break;
9396 
9397  case 3 :
9398  /* get hyperplane through p1, p2, p4 */
9399  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9400  &alpha, &beta, &gamma_, &delta) );
9401  /* if not underestimating in p3, then go to next candidate */
9402  if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9403  continue;
9404  break;
9405 
9406  case 4 :
9407  /* get hyperplane through p1, p2, p3 */
9408  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9409  &alpha, &beta, &gamma_, &delta) );
9410  /* if not underestimating in p4, then stop */
9411  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9412  continue;
9413  break;
9414 
9415  default: /* only for lint */
9416  alpha = SCIP_INVALID;
9417  beta = SCIP_INVALID;
9418  gamma_ = SCIP_INVALID;
9419  delta = SCIP_INVALID;
9420  break;
9421  }
9422 
9423  /* check if bad luck: should not happen if numerics are fine */
9424  if( SCIPisZero(scip, gamma_) )
9425  continue;
9426  assert(!SCIPisNegative(scip, gamma_));
9427 
9428  /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9429  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9430  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9431  continue;
9432 
9433  SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9434 
9435  /* value of hyperplane candidate in xstar */
9436  xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9437 
9438  /* if reaching target and first or better than previous candidate, then update */
9439  if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9440  {
9441  /* flip hyperplane */
9442  if( !overestimate )
9443  gamma_ = -gamma_;
9444 
9445  facetcoefs[0] = -alpha/gamma_;
9446  facetcoefs[1] = -beta/gamma_;
9447  *facetconstant = delta/gamma_;
9448 
9449  *success = TRUE;
9450  candxstarval = xstarval;
9451  }
9452  }
9453 
9454  return SCIP_OKAY;
9455 }
9456 
9457 /*
9458  * Callback methods of constraint handler
9459  */
9460 
9461 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
9462 static
9463 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
9464 { /*lint --e{715}*/
9465  SCIP_CONSHDLR* targetconshdlr;
9466  SCIP_CONSHDLRDATA* sourceconshdlrdata;
9467  int i;
9468 
9469  assert(scip != NULL);
9470  assert(conshdlr != NULL);
9471  assert(valid != NULL);
9472  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
9473 
9474  /* create basic data of constraint handler and include it to scip */
9476 
9477  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9478  assert(targetconshdlr != NULL);
9479  assert(targetconshdlr != conshdlr);
9480 
9481  sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
9482  assert(sourceconshdlrdata != NULL);
9483 
9484  /* copy nonlinear handlers */
9485  for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
9486  {
9487  SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
9488  }
9489 
9490  *valid = TRUE;
9491 
9492  return SCIP_OKAY;
9493 }
9494 
9495 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9496 static
9497 SCIP_DECL_CONSFREE(consFreeNonlinear)
9498 { /*lint --e{715}*/
9499  SCIP_CONSHDLRDATA* conshdlrdata;
9500  int i;
9501 
9502  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9503  assert(conshdlrdata != NULL);
9504 
9505  /* free nonlinear handlers */
9506  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9507  {
9508  SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
9509  assert(conshdlrdata->nlhdlrs[i] == NULL);
9510  }
9511  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
9512  conshdlrdata->nlhdlrssize = 0;
9513 
9514  /* free upgrade functions */
9515  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
9516  {
9517  assert(conshdlrdata->consupgrades[i] != NULL);
9518  SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
9519  }
9520  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
9521 
9522  SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
9523 
9524  SCIPqueueFree(&conshdlrdata->reversepropqueue);
9525 
9526  if( conshdlrdata->vp_randnumgen != NULL )
9527  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9528 
9529  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9530  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9531  {
9532  if( conshdlrdata->vp_lp[i] != NULL )
9533  {
9534  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9535  }
9536  }
9537 
9538  assert(conshdlrdata->branchrandnumgen == NULL);
9539 
9540  assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
9541  SCIPhashmapFree(&conshdlrdata->var2expr);
9542 
9543  SCIPfreeMemory(scip, &conshdlrdata);
9544  SCIPconshdlrSetData(conshdlr, NULL);
9545 
9546  return SCIP_OKAY;
9547 }
9548 
9549 
9550 /** initialization method of constraint handler (called after problem was transformed) */
9551 static
9552 SCIP_DECL_CONSINIT(consInitNonlinear)
9553 { /*lint --e{715}*/
9554  SCIP_CONSHDLRDATA* conshdlrdata;
9555  int i;
9556 
9557  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9558  assert(conshdlrdata != NULL);
9559 
9560  /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
9561  conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
9562  /* set to 1 so it is larger than initial value of lastenforound in exprs */
9563  conshdlrdata->enforound = 1;
9564  /* reset numbering for auxiliary variables */
9565  conshdlrdata->auxvarid = 0;
9566 
9567  for( i = 0; i < nconss; ++i )
9568  {
9569  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
9570  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
9571  }
9572 
9573  /* sort nonlinear handlers by detection priority, in decreasing order */
9574  if( conshdlrdata->nnlhdlrs > 1 )
9575  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
9576 
9577  /* get heuristics for later use */
9578  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9579  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9580 
9581  /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
9582  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9583  {
9584  SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
9585  }
9586 
9587  /* reset statistics in constraint handler */
9588  conshdlrdata->nweaksepa = 0;
9589  conshdlrdata->ntightenlp = 0;
9590  conshdlrdata->ndesperatebranch = 0;
9591  conshdlrdata->ndesperatecutoff = 0;
9592  conshdlrdata->ndesperatetightenlp = 0;
9593  conshdlrdata->nforcelp = 0;
9594  SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
9595  conshdlrdata->ncanonicalizecalls = 0;
9596 
9597 #ifdef ENFOLOGFILE
9598  ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
9599 #endif
9600 
9601  return SCIP_OKAY;
9602 }
9603 
9604 
9605 /** deinitialization method of constraint handler (called before transformed problem is freed) */
9606 static
9607 SCIP_DECL_CONSEXIT(consExitNonlinear)
9608 { /*lint --e{715}*/
9609  SCIP_CONSHDLRDATA* conshdlrdata;
9610  SCIP_CONS** consssorted;
9611  int i;
9612 
9613  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9614  assert(conshdlrdata != NULL);
9615 
9616  if( nconss > 0 )
9617  {
9618  /* for better performance of dropVarEvents, we sort by index, descending */
9619  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
9620  SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
9621 
9622  for( i = 0; i < nconss; ++i )
9623  {
9624  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
9625  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
9626  }
9627 
9628  SCIPfreeBufferArray(scip, &consssorted);
9629  }
9630 
9631  conshdlrdata->subnlpheur = NULL;
9632  conshdlrdata->trysolheur = NULL;
9633 
9634  if( conshdlrdata->vp_randnumgen != NULL )
9635  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9636 
9637  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9638  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9639  {
9640  if( conshdlrdata->vp_lp[i] != NULL )
9641  {
9642  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9643  }
9644  }
9645 
9646  if( conshdlrdata->branchrandnumgen != NULL )
9647  SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
9648 
9649  /* deinitialize nonlinear handlers */
9650  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9651  {
9652  SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
9653  }
9654 
9655  ENFOLOG(
9656  if( enfologfile != NULL )
9657  {
9658  fclose(enfologfile);
9659  enfologfile = NULL;
9660  })
9661 
9662  return SCIP_OKAY;
9663 }
9664 
9665 
9666 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
9667 #ifdef SCIP_DISABLED_CODE
9668 static
9670 { /*lint --e{715}*/
9671  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
9672  SCIPABORT(); /*lint --e{527}*/
9673 
9674  return SCIP_OKAY;
9675 }
9676 #else
9677 #define consInitpreNonlinear NULL
9678 #endif
9679 
9680 
9681 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9682 static
9683 SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
9684 { /*lint --e{715}*/
9685  SCIP_Bool infeasible;
9686 
9687  if( nconss == 0 )
9688  return SCIP_OKAY;
9689 
9690  /* skip some extra work if already known to be infeasible */
9691  if( SCIPgetStatus(scip) == SCIP_STATUS_INFEASIBLE )
9692  return SCIP_OKAY;
9693 
9694  /* simplify constraints and replace common subexpressions */
9695  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
9696 
9697  /* currently SCIP does not offer to communicate this,
9698  * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
9699  * or if a constraint expression became constant
9700  */
9701  assert(!infeasible);
9702 
9703  /* tell SCIP that we have something nonlinear */
9704  SCIPenableNLP(scip);
9705 
9706  return SCIP_OKAY;
9707 }
9708 
9709 
9710 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
9711 static
9712 SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
9713 { /*lint --e{715}*/
9714  SCIP_CONSHDLRDATA* conshdlrdata;
9715  int i;
9716 
9717  /* skip remaining initializations if we have solved already
9718  * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
9719  * assumes nonempty activities in expressions
9720  */
9721  switch( SCIPgetStatus(scip) )
9722  {
9723  case SCIP_STATUS_OPTIMAL:
9725  case SCIP_STATUS_UNBOUNDED:
9726  case SCIP_STATUS_INFORUNBD:
9727  return SCIP_OKAY;
9728  default: ;
9729  } /*lint !e788 */
9730 
9731  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9732  assert(conshdlrdata != NULL);
9733 
9734  /* reset one of the number of detections counter to count only current round */
9735  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9736  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
9737 
9738  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
9739 
9740  /* catch new solution event */
9741  if( nconss != 0 && conshdlrdata->linearizeheursol != 'o' )
9742  {
9743  SCIP_EVENTHDLR* eventhdlr;
9744 
9745  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9746  assert(eventhdlr != NULL);
9747 
9748  SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
9749  eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9750  }
9751 
9752  /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
9753  if( conshdlrdata->branchpscostweight > 0.0 )
9754  {
9755  SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
9756  if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
9757  {
9758  SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
9759  SCIPABORT();
9760  return SCIP_INVALIDDATA;
9761  }
9762  }
9763 
9764  return SCIP_OKAY;
9765 }
9766 
9767 
9768 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9769 static
9770 SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
9771 { /*lint --e{715}*/
9772  SCIP_CONSHDLRDATA* conshdlrdata;
9773 
9774  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
9775 
9776  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9777  assert(conshdlrdata != NULL);
9778 
9779  /* free hash table for bilinear terms */
9780  SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
9781 
9782  /* reset flag to allow another call of presolSingleLockedVars() after a restart */
9783  conshdlrdata->checkedvarlocks = FALSE;
9784 
9785  /* drop catching new solution event, if catched before */
9786  if( conshdlrdata->newsoleventfilterpos >= 0 )
9787  {
9788  SCIP_EVENTHDLR* eventhdlr;
9789 
9790  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9791  assert(eventhdlr != NULL);
9792 
9793  SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9794  conshdlrdata->newsoleventfilterpos = -1;
9795  }
9796 
9797  return SCIP_OKAY;
9798 }
9799 
9800 
9801 /** frees specific constraint data */
9802 static
9803 SCIP_DECL_CONSDELETE(consDeleteNonlinear)
9804 { /*lint --e{715}*/
9805  assert(consdata != NULL);
9806  assert(*consdata != NULL);
9807  assert((*consdata)->expr != NULL);
9808 
9809  /* constraint locks should have been removed */
9810  assert((*consdata)->nlockspos == 0);
9811  assert((*consdata)->nlocksneg == 0);
9812 
9813  /* free variable expressions */
9814  SCIP_CALL( freeVarExprs(scip, *consdata) );
9815 
9816  SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
9817 
9818  /* free nonlinear row representation */
9819  if( (*consdata)->nlrow != NULL )
9820  {
9821  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
9822  }
9823 
9824  SCIPfreeBlockMemory(scip, consdata);
9825 
9826  return SCIP_OKAY;
9827 }
9828 
9829 
9830 /** transforms constraint data into data belonging to the transformed problem */
9831 static
9832 SCIP_DECL_CONSTRANS(consTransNonlinear)
9833 { /*lint --e{715}*/
9834  SCIP_EXPR* targetexpr;
9835  SCIP_CONSDATA* sourcedata;
9836 
9837  sourcedata = SCIPconsGetData(sourcecons);
9838  assert(sourcedata != NULL);
9839 
9840  /* get a copy of sourceexpr with transformed vars */
9841  SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
9842  assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
9843 
9844  /* create transformed cons (only captures targetexpr, no need to copy again) */
9845  SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
9846  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
9847  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
9848  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
9849  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
9850  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
9851 
9852  /* release target expr */
9853  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
9854 
9855  return SCIP_OKAY;
9856 }
9857 
9858 
9859 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9860 static
9861 SCIP_DECL_CONSINITLP(consInitlpNonlinear)
9862 { /*lint --e{715}*/
9863  /* create auxiliary variables and call separation initialization callbacks of the expression handlers
9864  * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
9865  * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
9866  * for now, there is an assert in detectNlhdlrs to require initial if separated
9867  */
9868  SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
9869 
9870  /* collect all bilinear terms for which an auxvar is present
9871  * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
9872  * addition (and removal?) of constraints during solve
9873  * this is typically the majority of constraints, but the method should be made more flexible
9874  */
9875  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
9876 
9877  return SCIP_OKAY;
9878 }
9879 
9880 
9881 /** separation method of constraint handler for LP solutions */
9882 static
9883 SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
9884 { /*lint --e{715}*/
9885  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
9886 
9887  return SCIP_OKAY;
9888 }
9889 
9890 
9891 /** separation method of constraint handler for arbitrary primal solutions */
9892 static
9893 SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
9894 { /*lint --e{715}*/
9895  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
9896 
9897  return SCIP_OKAY;
9898 }
9899 
9900 
9901 /** constraint enforcing method of constraint handler for LP solutions */
9902 static
9903 SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
9904 { /*lint --e{715}*/
9905  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
9906 
9907  return SCIP_OKAY;
9908 }
9909 
9910 
9911 /** constraint enforcing method of constraint handler for relaxation solutions */
9912 static
9913 SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
9914 { /*lint --e{715}*/
9915  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
9916 
9917  return SCIP_OKAY;
9918 }
9919 
9920 
9921 /** constraint enforcing method of constraint handler for pseudo solutions */
9922 static
9923 SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
9924 { /*lint --e{715}*/
9925  SCIP_RESULT propresult;
9926  SCIP_Longint soltag;
9927  int nchgbds;
9928  int nnotify;
9929  int c;
9930 
9931  soltag = SCIPgetExprNewSoltag(scip);
9932 
9933  *result = SCIP_FEASIBLE;
9934  for( c = 0; c < nconss; ++c )
9935  {
9936  SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
9937 
9938  if( isConsViolated(scip, conss[c]) )
9939  *result = SCIP_INFEASIBLE;
9940  }
9941 
9942  if( *result == SCIP_FEASIBLE )
9943  return SCIP_OKAY;
9944 
9945  /* try to propagate
9946  * TODO obey propinenfo parameter, but we need something to recognize cutoff
9947  */
9948  nchgbds = 0;
9949  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
9950 
9951  if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
9952  {
9953  *result = propresult;
9954  return SCIP_OKAY;
9955  }
9956 
9957  /* register all unfixed variables in all violated constraints as branching candidates */
9958  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
9959  if( nnotify > 0 )
9960  {
9961  SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
9962 
9963  return SCIP_OKAY;
9964  }
9965 
9966  SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
9967  *result = SCIP_SOLVELP;
9968  ++SCIPconshdlrGetData(conshdlr)->nforcelp;
9969 
9970  return SCIP_OKAY;
9971 }
9972 
9973 
9974 /** feasibility check method of constraint handler for integral solutions */
9975 static
9976 SCIP_DECL_CONSCHECK(consCheckNonlinear)
9977 { /*lint --e{715}*/
9978  SCIP_CONSHDLRDATA* conshdlrdata;
9979  SCIP_CONSDATA* consdata;
9980  SCIP_Real maxviol;
9981  SCIP_Bool maypropfeasible;
9982  SCIP_Longint soltag;
9983  int c;
9984 
9985  assert(scip != NULL);
9986  assert(conshdlr != NULL);
9987  assert(conss != NULL || nconss == 0);
9988  assert(result != NULL);
9989 
9990  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9991  assert(conshdlrdata != NULL);
9992 
9993  *result = SCIP_FEASIBLE;
9994  soltag = SCIPgetExprNewSoltag(scip);
9995  maxviol = 0.0;
9996  maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
9997  && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING;
9998 
9999  /* check nonlinear constraints for feasibility */
10000  for( c = 0; c < nconss; ++c )
10001  {
10002  assert(conss != NULL && conss[c] != NULL);
10003  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
10004 
10005  if( isConsViolated(scip, conss[c]) )
10006  {
10007  *result = SCIP_INFEASIBLE;
10008  maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
10009 
10010  consdata = SCIPconsGetData(conss[c]);
10011  assert(consdata != NULL);
10012 
10013  /* print reason for infeasibility */
10014  if( printreason )
10015  {
10016  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
10017  SCIPinfoMessage(scip, NULL, ";\n");
10018 
10019  if( consdata->lhsviol > SCIPfeastol(scip) )
10020  {
10021  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
10022  }
10023  if( consdata->rhsviol > SCIPfeastol(scip) )
10024  {
10025  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
10026  }
10027  }
10028  else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
10029  {
10030  /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
10031  return SCIP_OKAY;
10032  }
10033 
10034  /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
10035  if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
10036  maypropfeasible = FALSE;
10037 
10038  if( maypropfeasible )
10039  {
10040  if( consdata->lhsviol > SCIPfeastol(scip) )
10041  {
10042  /* check if there is a variable which may help to get the left hand side satisfied
10043  * if there is no such variable, then we cannot get feasible
10044  */
10045  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
10046  !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
10047  maypropfeasible = FALSE;
10048  }
10049  else
10050  {
10051  assert(consdata->rhsviol > SCIPfeastol(scip));
10052  /* check if there is a variable which may help to get the right hand side satisfied
10053  * if there is no such variable, then we cannot get feasible
10054  */
10055  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
10056  !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
10057  maypropfeasible = FALSE;
10058  }
10059  }
10060  }
10061  }
10062 
10063  if( *result == SCIP_INFEASIBLE && maypropfeasible )
10064  {
10065  SCIP_Bool success;
10066 
10067  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
10068 
10069  /* do not pass solution to NLP heuristic if we made it feasible this way */
10070  if( success )
10071  return SCIP_OKAY;
10072  }
10073 
10074  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
10075  {
10076  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
10077  }
10078 
10079  return SCIP_OKAY;
10080 }
10081 
10082 
10083 /** domain propagation method of constraint handler */
10084 static
10085 SCIP_DECL_CONSPROP(consPropNonlinear)
10086 { /*lint --e{715}*/
10087  int nchgbds = 0;
10088 
10089  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
10090  assert(nchgbds >= 0);
10091 
10092  /* TODO would it make sense to check for redundant constraints? */
10093 
10094  return SCIP_OKAY;
10095 }
10096 
10097 
10098 /** presolving method of constraint handler */
10099 static
10100 SCIP_DECL_CONSPRESOL(consPresolNonlinear)
10101 { /*lint --e{715}*/
10102  SCIP_CONSHDLRDATA* conshdlrdata;
10103  SCIP_Bool infeasible;
10104  int c;
10105 
10106  *result = SCIP_DIDNOTFIND;
10107 
10108  if( nconss == 0 )
10109  {
10110  *result = SCIP_DIDNOTRUN;
10111  return SCIP_OKAY;
10112  }
10113 
10114  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10115  assert(conshdlrdata != NULL);
10116 
10117  /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
10118  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
10119  if( infeasible )
10120  {
10121  *result = SCIP_CUTOFF;
10122  return SCIP_OKAY;
10123  }
10124 
10125  /* merge constraints with the same root expression */
10126  if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
10127  {
10128  SCIP_Bool success;
10129 
10130  SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
10131  if( success )
10132  *result = SCIP_SUCCESS;
10133  }
10134 
10135  /* propagate constraints */
10136  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
10137  if( *result == SCIP_CUTOFF )
10138  return SCIP_OKAY;
10139 
10140  /* propagate function domains (TODO integrate with simplify?) */
10141  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
10142  {
10143  SCIP_RESULT localresult;
10144  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
10145  if( localresult == SCIP_CUTOFF )
10146  {
10147  *result = SCIP_CUTOFF;
10148  return SCIP_OKAY;
10149  }
10150  if( localresult == SCIP_REDUCEDDOM )
10151  *result = SCIP_REDUCEDDOM;
10152  }
10153 
10154  /* check for redundant constraints, remove constraints that are a value expression */
10155  SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
10156  if( infeasible )
10157  {
10158  *result = SCIP_CUTOFF;
10159  return SCIP_OKAY;
10160  }
10161 
10162  /* try to upgrade constraints */
10163  for( c = 0; c < nconss; ++c )
10164  {
10165  SCIP_Bool upgraded;
10166 
10167  /* skip inactive and deleted constraints */
10168  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
10169  continue;
10170 
10171  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10172  }
10173 
10174  /* try to change continuous variables that appear linearly to be implicit integer */
10175  if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
10176  {
10177  SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
10178 
10179  if( infeasible )
10180  {
10181  SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
10182  *result = SCIP_CUTOFF;
10183  return SCIP_OKAY;
10184  }
10185  }
10186 
10187  /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
10188  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) && SCIPisPresolveFinished(scip)
10189  && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
10190  {
10191  /* run this presolving technique only once because we don't want to generate identical bound disjunction
10192  * constraints multiple times
10193  */
10194  conshdlrdata->checkedvarlocks = TRUE;
10195 
10196  for( c = 0; c < nconss; ++c )
10197  {
10198  int tmpnchgvartypes = 0;
10199  int tmpnaddconss = 0;
10200 
10201  SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
10202  SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
10203  SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
10204 
10205  if( infeasible )
10206  {
10207  SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
10208  *result = SCIP_CUTOFF;
10209  return SCIP_OKAY;
10210  }
10211 
10212  (*nchgvartypes) += tmpnchgvartypes;
10213  (*naddconss) += tmpnaddconss;
10214  }
10215  }
10216 
10217  if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
10218  *result = SCIP_SUCCESS;
10219  else
10220  *result = SCIP_DIDNOTFIND;
10221 
10222  return SCIP_OKAY;
10223 }
10224 
10225 
10226 /** propagation conflict resolving method of constraint handler */
10227 #ifdef SCIP_DISABLED_CODE
10228 static
10230 { /*lint --e{715}*/
10231  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10232  SCIPABORT(); /*lint --e{527}*/
10233 
10234  return SCIP_OKAY;
10235 }
10236 #else
10237 #define consRespropNonlinear NULL
10238 #endif
10239 
10240 
10241 /** variable rounding lock method of constraint handler */
10242 static
10243 SCIP_DECL_CONSLOCK(consLockNonlinear)
10244 { /*lint --e{715}*/
10245  SCIP_CONSDATA* consdata;
10246  SCIP_EXPR_OWNERDATA* ownerdata;
10247  SCIP_Bool reinitsolve = FALSE;
10248 
10249  assert(conshdlr != NULL);
10250  assert(cons != NULL);
10251 
10252  consdata = SCIPconsGetData(cons);
10253  assert(consdata != NULL);
10254  assert(consdata->expr != NULL);
10255 
10256  ownerdata = SCIPexprGetOwnerData(consdata->expr);
10257 
10258  /* check whether we need to initSolve again because
10259  * - we have enfo initialized (nenfos >= 0)
10260  * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
10261  */
10262  if( ownerdata->nenfos >= 0 )
10263  {
10264  if( (consdata->nlockspos == 0) != (nlockspos == 0) )
10265  reinitsolve = TRUE;
10266  if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
10267  reinitsolve = TRUE;
10268  }
10269 
10270  if( reinitsolve )
10271  {
10272  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10273  }
10274 
10275  /* add locks */
10276  SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
10277 
10278  if( reinitsolve )
10279  {
10280  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10281  }
10282 
10283  return SCIP_OKAY;
10284 }
10285 
10286 
10287 /** constraint activation notification method of constraint handler */
10288 static
10289 SCIP_DECL_CONSACTIVE(consActiveNonlinear)
10290 { /*lint --e{715}*/
10291  SCIP_CONSDATA* consdata;
10292  SCIP_Bool infeasible = FALSE;
10293 
10294  consdata = SCIPconsGetData(cons);
10295  assert(consdata != NULL);
10296 
10297  /* simplify root expression if the constraint has been added after presolving */
10299  {
10300  SCIP_Bool replacedroot;
10301 
10302  if( !consdata->issimplified )
10303  {
10304  SCIP_EXPR* simplified;
10305  SCIP_Bool changed;
10306 
10307  /* simplify constraint */
10308  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
10309  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
10310  assert(simplified != NULL);
10311  consdata->expr = simplified;
10312  consdata->issimplified = TRUE;
10313  }
10314 
10315  /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
10316  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
10317  assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
10318 
10319  /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
10320  {
10321  SCIP_CONSHDLRDATA* conshdlrdata;
10322  SCIP_EXPRITER* it;
10323  SCIP_EXPR* expr;
10324 
10325  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10326  assert(conshdlrdata != NULL);
10327 
10328  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
10329  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
10331  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10332  {
10333  SCIP_EXPR* child;
10334  SCIP_EXPR* hashmapexpr;
10335 
10336  child = SCIPexpriterGetChildExprDFS(it);
10337  if( !SCIPisExprVar(scip, child) )
10338  continue;
10339 
10340  /* check which expression is stored in the hashmap for the var of child */
10341  hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
10342  /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
10343  if( hashmapexpr != NULL && hashmapexpr != child )
10344  {
10345  SCIP_CALL( SCIPreplaceExprChild(scip, expr, SCIPexpriterGetChildIdxDFS(it), hashmapexpr) );
10346  }
10347  }
10348  SCIPfreeExpriter(&it);
10349  }
10350  }
10351 
10352  /* store variable expressions */
10353  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10354  {
10355  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10356  }
10357 
10358  /* add manually locks to constraints that are not checked for feasibility */
10359  if( !SCIPconsIsChecked(cons) )
10360  {
10361  assert(consdata->nlockspos == 0);
10362  assert(consdata->nlocksneg == 0);
10363 
10364  SCIP_CALL( addLocks(scip, cons, 1, 0) );
10365  }
10366 
10367  if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
10368  {
10369  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10370  }
10371 
10372  /* TODO deal with infeasibility */
10373  assert(!infeasible);
10374 
10375  return SCIP_OKAY;
10376 }
10377 
10378 
10379 /** constraint deactivation notification method of constraint handler */
10380 static
10381 SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
10382 { /*lint --e{715}*/
10383  SCIP_CONSHDLRDATA* conshdlrdata;
10384 
10385  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10386  assert(conshdlrdata != NULL);
10387 
10388  if( SCIPgetStage(scip) < SCIP_STAGE_EXITSOLVE )
10389  {
10390  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10391  }
10392 
10393  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10394  {
10395  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10396  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(cons)) );
10397  }
10398 
10399  /* remove locks that have been added in consActiveExpr() */
10400  if( !SCIPconsIsChecked(cons) )
10401  {
10402  SCIP_CALL( addLocks(scip, cons, -1, 0) );
10403 
10404  assert(SCIPconsGetData(cons)->nlockspos == 0);
10405  assert(SCIPconsGetData(cons)->nlocksneg == 0);
10406  }
10407 
10408  return SCIP_OKAY;
10409 }
10410 
10411 
10412 /** constraint enabling notification method of constraint handler */
10413 static
10414 SCIP_DECL_CONSENABLE(consEnableNonlinear)
10415 { /*lint --e{715}*/
10416  SCIP_CONSHDLRDATA* conshdlrdata;
10417 
10418  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10419  assert(conshdlrdata != NULL);
10420 
10421  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10422  {
10423  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10424  }
10425 
10426  return SCIP_OKAY;
10427 }
10428 
10429 
10430 /** constraint disabling notification method of constraint handler */
10431 static
10432 SCIP_DECL_CONSDISABLE(consDisableNonlinear)
10433 { /*lint --e{715}*/
10434  SCIP_CONSHDLRDATA* conshdlrdata;
10435 
10436  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10437  assert(conshdlrdata != NULL);
10438 
10439  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10440  {
10441  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10442  }
10443 
10444  return SCIP_OKAY;
10445 }
10446 
10447 /** variable deletion of constraint handler */
10448 #ifdef SCIP_DISABLED_CODE
10449 static
10451 { /*lint --e{715}*/
10452  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10453  SCIPABORT(); /*lint --e{527}*/
10454 
10455  return SCIP_OKAY;
10456 }
10457 #else
10458 #define consDelvarsNonlinear NULL
10459 #endif
10460 
10461 
10462 /** constraint display method of constraint handler */
10463 static
10464 SCIP_DECL_CONSPRINT(consPrintNonlinear)
10465 { /*lint --e{715}*/
10466  SCIP_CONSDATA* consdata;
10467 
10468  consdata = SCIPconsGetData(cons);
10469  assert(consdata != NULL);
10470  assert(consdata->expr != NULL);
10471 
10472  /* print left hand side for ranged constraints */
10473  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10474  {
10475  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10476  }
10477 
10478  /* print expression */
10479  SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
10480 
10481  /* print right hand side */
10482  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10483  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
10484  else if( !SCIPisInfinity(scip, consdata->rhs) )
10485  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
10486  else if( !SCIPisInfinity(scip, -consdata->lhs) )
10487  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
10488  else
10489  SCIPinfoMessage(scip, file, " [free]");
10490 
10491  return SCIP_OKAY;
10492 }
10493 
10494 
10495 /** constraint copying method of constraint handler */
10496 static
10497 SCIP_DECL_CONSCOPY(consCopyNonlinear)
10498 { /*lint --e{715}*/
10499  SCIP_CONSHDLR* targetconshdlr;
10500  SCIP_EXPR* targetexpr = NULL;
10501  SCIP_CONSDATA* sourcedata;
10502 
10503  assert(cons != NULL);
10504 
10505  sourcedata = SCIPconsGetData(sourcecons);
10506  assert(sourcedata != NULL);
10507 
10508  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10509  assert(targetconshdlr != NULL);
10510 
10511  SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
10512 
10513  if( targetexpr == NULL )
10514  *valid = FALSE;
10515 
10516  *cons = NULL;
10517  if( *valid )
10518  {
10519  /* create copy (only capture targetexpr, no need to copy again) */
10520  SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
10521  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
10522  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10523  }
10524 
10525  if( targetexpr != NULL )
10526  {
10527  /* release target expr */
10528  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
10529  }
10530 
10531  return SCIP_OKAY;
10532 }
10533 
10534 
10535 /** constraint parsing method of constraint handler */
10536 static
10537 SCIP_DECL_CONSPARSE(consParseNonlinear)
10538 { /*lint --e{715}*/
10539  SCIP_Real lhs;
10540  SCIP_Real rhs;
10541  const char* endptr;
10542  SCIP_EXPR* consexprtree;
10543 
10544  SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
10545 
10546  assert(scip != NULL);
10547  assert(success != NULL);
10548  assert(str != NULL);
10549  assert(name != NULL);
10550  assert(cons != NULL);
10551 
10552  *success = FALSE;
10553 
10554  /* return if string empty */
10555  if( !*str )
10556  return SCIP_OKAY;
10557 
10558  endptr = str;
10559 
10560  /* set left and right hand side to their default values */
10561  lhs = -SCIPinfinity(scip);
10562  rhs = SCIPinfinity(scip);
10563 
10564  /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
10565 
10566  /* check for left hand side */
10567  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
10568  {
10569  /* there is a number coming, maybe it is a left-hand-side */
10570  if( !SCIPstrToRealValue(str, &lhs, (char**)&endptr) )
10571  {
10572  SCIPerrorMessage("error parsing number from <%s>\n", str);
10573  return SCIP_READERROR;
10574  }
10575 
10576  /* ignore whitespace */
10577  while( isspace((unsigned char)*endptr) )
10578  ++endptr;
10579 
10580  if( endptr[0] != '<' || endptr[1] != '=' )
10581  {
10582  /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
10583  lhs = -SCIPinfinity(scip);
10584  }
10585  else
10586  {
10587  /* it was indeed a left-hand-side, so continue parsing after it */
10588  str = endptr + 2;
10589 
10590  /* ignore whitespace */
10591  while( isspace((unsigned char)*str) )
10592  ++str;
10593  }
10594  }
10595 
10596  SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
10597 
10598  /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
10599  SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
10600 
10601  /* check for left or right hand side */
10602  while( isspace((unsigned char)*str) )
10603  ++str;
10604 
10605  /* check for free constraint */
10606  if( strncmp(str, "[free]", 6) == 0 )
10607  {
10608  if( !SCIPisInfinity(scip, -lhs) )
10609  {
10610  SCIPerrorMessage("cannot have left hand side and [free] status \n");
10611  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10612  return SCIP_OKAY;
10613  }
10614  *success = TRUE;
10615  }
10616  else
10617  {
10618  switch( *str )
10619  {
10620  case '<':
10621  *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10622  break;
10623  case '=':
10624  if( !SCIPisInfinity(scip, -lhs) )
10625  {
10626  SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
10627  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10628  return SCIP_OKAY;
10629  }
10630  else
10631  {
10632  *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10633  lhs = rhs;
10634  }
10635  break;
10636  case '>':
10637  if( !SCIPisInfinity(scip, -lhs) )
10638  {
10639  SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
10640  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10641  return SCIP_OKAY;
10642  }
10643  else
10644  {
10645  *success = SCIPstrToRealValue(str+2, &lhs, (char**)&endptr);
10646  break;
10647  }
10648  case '\0':
10649  *success = TRUE;
10650  break;
10651  default:
10652  SCIPerrorMessage("unexpected character %c\n", *str);
10653  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10654  return SCIP_OKAY;
10655  }
10656  }
10657 
10658  /* create constraint */
10659  SCIP_CALL( createCons(scip, conshdlr, cons, name,
10660  consexprtree, lhs, rhs, FALSE,
10661  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10662  assert(*cons != NULL);
10663 
10664  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10665 
10666  SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
10667 
10668  return SCIP_OKAY;
10669 }
10670 
10671 
10672 /** constraint method of constraint handler which returns the variables (if possible) */
10673 static
10674 SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
10675 { /*lint --e{715}*/
10676  SCIP_CONSDATA* consdata;
10677  int i;
10678 
10679  consdata = SCIPconsGetData(cons);
10680  assert(consdata != NULL);
10681 
10682  /* store variable expressions if not done so far */
10683  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10684 
10685  /* check whether array is too small in order to store all variables */
10686  if( varssize < consdata->nvarexprs )
10687  {
10688  *success = FALSE;
10689  return SCIP_OKAY;
10690  }
10691 
10692  for( i = 0; i < consdata->nvarexprs; ++i )
10693  {
10694  vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
10695  assert(vars[i] != NULL);
10696  }
10697 
10698  *success = TRUE;
10699 
10700  return SCIP_OKAY;
10701 }
10702 
10703 /** constraint method of constraint handler which returns the number of variables (if possible) */
10704 static
10705 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
10706 { /*lint --e{715}*/
10707  SCIP_CONSDATA* consdata;
10708 
10709  consdata = SCIPconsGetData(cons);
10710  assert(consdata != NULL);
10711 
10712  /* store variable expressions if not done so far */
10713  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10714 
10715  *nvars = consdata->nvarexprs;
10716  *success = TRUE;
10717 
10718  return SCIP_OKAY;
10719 }
10720 
10721 /** constraint handler method to suggest dive bound changes during the generic diving algorithm */
10722 #ifdef SCIP_DISABLED_CODE
10723 static
10725 { /*lint --e{715}*/
10726  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10727  SCIPABORT(); /*lint --e{527}*/
10728 
10729  return SCIP_OKAY;
10730 }
10731 #else
10732 #define consGetDiveBdChgsNonlinear NULL
10733 #endif
10734 
10735 /** output method of statistics table to output file stream 'file' */
10736 static
10737 SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
10738 { /*lint --e{715}*/
10739  SCIP_CONSHDLR* conshdlr;
10740  SCIP_CONSHDLRDATA* conshdlrdata;
10741 
10742  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10743  assert(conshdlr != NULL);
10744 
10745  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10746  assert(conshdlrdata != NULL);
10747 
10748  /* print statistics for constraint handler */
10749  SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
10750  SCIPinfoMessage(scip, file, " enforce%-10s:", "");
10751  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
10752  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
10753  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
10754  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
10755  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
10756  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
10757  SCIPinfoMessage(scip, file, "\n");
10758  SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
10759  SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
10760  SCIPinfoMessage(scip, file, "\n");
10761 
10762  return SCIP_OKAY;
10763 }
10764 
10765 /** output method of statistics table to output file stream 'file' */
10766 static
10767 SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
10768 { /*lint --e{715}*/
10769  SCIP_CONSHDLR* conshdlr;
10770  SCIP_CONSHDLRDATA* conshdlrdata;
10771 
10772  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10773  assert(conshdlr != NULL);
10774 
10775  /* skip nlhdlr table if there never were active nonlinear constraints */
10776  if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
10777  return SCIP_OKAY;
10778 
10779  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10780  assert(conshdlrdata != NULL);
10781 
10782  /* print statistics for nonlinear handlers */
10783  SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
10784 
10785  return SCIP_OKAY;
10786 }
10787 
10788 /** execution method of display nlhdlrs dialog */
10789 static
10790 SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
10791 { /*lint --e{715}*/
10792  SCIP_CONSHDLR* conshdlr;
10793  SCIP_CONSHDLRDATA* conshdlrdata;
10794  int i;
10795 
10796  /* add dialog to history of dialogs that have been executed */
10797  SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
10798 
10799  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10800  assert(conshdlr != NULL);
10801 
10802  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10803  assert(conshdlrdata != NULL);
10804 
10805  /* display list of nonlinear handler */
10806  SCIPdialogMessage(scip, NULL, "\n");
10807  SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
10808  SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
10809  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10810  {
10811  SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
10812  assert(nlhdlr != NULL);
10813 
10814  SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
10815  SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
10816  SCIPdialogMessage(scip, NULL, " %10d ", SCIPnlhdlrGetDetectPriority(nlhdlr));
10817  SCIPdialogMessage(scip, NULL, " %11d ", SCIPnlhdlrGetEnfoPriority(nlhdlr));
10818  SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
10819  SCIPdialogMessage(scip, NULL, "\n");
10820  }
10821  SCIPdialogMessage(scip, NULL, "\n");
10822 
10823  /* next dialog will be root dialog again */
10824  *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
10825 
10826  return SCIP_OKAY;
10827 }
10828 
10829 /*
10830  * constraint handler specific interface methods
10831  */
10832 
10833 /** creates the handler for nonlinear constraints and includes it in SCIP */
10835  SCIP* scip /**< SCIP data structure */
10836  )
10837 {
10838  SCIP_CONSHDLRDATA* conshdlrdata;
10839  SCIP_DIALOG* parentdialog;
10840 
10841  /* create nonlinear constraint handler data */
10842  SCIP_CALL( SCIPallocClearMemory(scip, &conshdlrdata) );
10843  conshdlrdata->intevalvar = intEvalVarBoundTightening;
10844  conshdlrdata->curboundstag = 1;
10845  conshdlrdata->lastboundrelax = 1;
10846  conshdlrdata->curpropboundstag = 1;
10847  conshdlrdata->newsoleventfilterpos = -1;
10848  SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
10849  SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
10850  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
10851 
10852  /* include constraint handler */
10858  conshdlrCopyNonlinear,
10859  consFreeNonlinear, consInitNonlinear, consExitNonlinear,
10860  consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
10861  consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
10862  consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
10863  consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
10864  consActiveNonlinear, consDeactiveNonlinear,
10865  consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
10866  consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
10867  consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, conshdlrdata) );
10868 
10869  /* add nonlinear constraint handler parameters */
10870  /* TODO organize into more subcategories */
10871  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
10872  "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
10873  &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
10874 
10875  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
10876  "whether to check bounds of all auxiliary variable to seed reverse propagation",
10877  &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
10878 
10879  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
10880  "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",
10881  &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
10882 
10883  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
10884  "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
10885  &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10886 
10887  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
10888  "by how much to relax constraint sides during bound tightening",
10889  &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10890 
10891  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
10892  "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
10893  &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
10894 
10895  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
10896  "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
10897  &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
10898 
10899  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
10900  "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
10901  &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
10902 
10903  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
10904  "maximal number of auxiliary expressions per bilinear term",
10905  &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
10906 
10907  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
10908  "whether to reformulate products of binary variables during presolving",
10909  &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
10910 
10911  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
10912  "whether to use the AND constraint handler for reformulating binary products",
10913  &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
10914 
10915  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
10916  "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
10917  &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
10918 
10919  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
10920  "whether to forbid multiaggregation of nonlinear variables",
10921  &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
10922 
10923  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
10924  "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
10925  &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
10926 
10927  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
10928  "whether to (re)run propagation in enforcement",
10929  &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
10930 
10931  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
10932  "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
10933  &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
10934 
10935  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
10936  "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
10937  &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
10938 
10939  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
10940  "consider efficacy requirement when deciding whether a cut is \"strong\"",
10941  &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
10942 
10943  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
10944  "whether to force \"strong\" cuts in enforcement",
10945  &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
10946 
10947  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
10948  "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
10949  &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
10950 
10951  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
10952  "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
10953  &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
10954 
10955  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
10956  "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",
10957  &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
10958 
10959  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
10960  "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
10961  &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
10962 
10963  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
10964  "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)",
10965  &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
10966 
10967  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
10968  "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
10969  &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
10970 
10971  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
10972  "whether to use external branching candidates and branching rules for branching",
10973  &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
10974 
10975  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
10976  "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
10977  &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
10978 
10979  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
10980  "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
10981  &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
10982 
10983  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
10984  "weight by how much to consider the violation assigned to a variable for its branching score",
10985  &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10986 
10987  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
10988  "weight by how much to consider the dual values of rows that contain a variable for its branching score",
10989  &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10990 
10991  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
10992  "weight by how much to consider the pseudo cost of a variable for its branching score",
10993  &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10994 
10995  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
10996  "weight by how much to consider the domain width in branching score",
10997  &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10998 
10999  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
11000  "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
11001  &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
11002 
11003  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
11004  "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
11005  &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
11006 
11007  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
11008  "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
11009  &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
11010 
11011  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
11012  "minimum pseudo-cost update count required to consider pseudo-costs reliable",
11013  &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11014 
11015  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
11016  "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)",
11017  &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
11018 
11019  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
11020  "whether to assume that any constraint is convex",
11021  &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
11022 
11023  /* include handler for bound change events */
11024  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
11025  "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
11026  assert(conshdlrdata->eventhdlr != NULL);
11027 
11028  /* include tables for statistics */
11029  assert(SCIPfindTable(scip, TABLE_NAME_NONLINEAR) == NULL);
11031  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
11033 
11034  assert(SCIPfindTable(scip, TABLE_NAME_NLHDLR) == NULL);
11036  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
11038 
11039  /* create, include, and release display nlhdlrs dialog */
11040  if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
11041  {
11042  SCIP_DIALOG* dialog;
11043 
11044  assert(parentdialog != NULL);
11045  assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
11046 
11047  SCIP_CALL( SCIPincludeDialog(scip, &dialog,
11048  NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
11050  SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
11051  SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
11052  }
11053 
11054  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
11055  processNewSolutionEvent, NULL) );
11056 
11057  return SCIP_OKAY;
11058 }
11059 
11060 /** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
11062  SCIP* scip, /**< SCIP data structure */
11063  SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
11064  int priority, /**< priority of upgrading method */
11065  SCIP_Bool active, /**< should the upgrading method by active by default? */
11066  const char* conshdlrname /**< name of the constraint handler */
11067  )
11068 {
11069  SCIP_CONSHDLR* conshdlr;
11070  SCIP_CONSHDLRDATA* conshdlrdata;
11071  CONSUPGRADE* consupgrade;
11072  char paramname[SCIP_MAXSTRLEN];
11073  char paramdesc[SCIP_MAXSTRLEN];
11074  int i;
11075 
11076  assert(conshdlrname != NULL );
11077  assert(nlconsupgd != NULL);
11078 
11079  /* find the nonlinear constraint handler */
11080  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11081  if( conshdlr == NULL )
11082  {
11083  SCIPerrorMessage("nonlinear constraint handler not found\n");
11084  return SCIP_PLUGINNOTFOUND;
11085  }
11086 
11087  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11088  assert(conshdlrdata != NULL);
11089 
11090  /* check whether upgrade method exists already */
11091  for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
11092  {
11093  if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
11094  {
11095 #ifdef SCIP_DEBUG
11096  SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
11097 #endif
11098  return SCIP_OKAY;
11099  }
11100  }
11101 
11102  /* create a nonlinear constraint upgrade data object */
11103  SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
11104  consupgrade->consupgd = nlconsupgd;
11105  consupgrade->priority = priority;
11106  consupgrade->active = active;
11107 
11108  /* insert nonlinear constraint upgrade method into constraint handler data */
11109  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
11110  assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
11111 
11112  for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
11113  conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
11114  assert(0 <= i && i <= conshdlrdata->nconsupgrades);
11115  conshdlrdata->consupgrades[i] = consupgrade;
11116  conshdlrdata->nconsupgrades++;
11117 
11118  /* adds parameter to turn on and off the upgrading step */
11119  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
11120  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
11122  paramname, paramdesc,
11123  &consupgrade->active, FALSE, active, NULL, NULL) );
11124 
11125  return SCIP_OKAY;
11126 }
11127 
11128 /** creates and captures a nonlinear constraint
11129  *
11130  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11131  */
11133  SCIP* scip, /**< SCIP data structure */
11134  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11135  const char* name, /**< name of constraint */
11136  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11137  SCIP_Real lhs, /**< left hand side of constraint */
11138  SCIP_Real rhs, /**< right hand side of constraint */
11139  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11140  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11141  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11142  * Usually set to TRUE. */
11143  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11144  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11145  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11146  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11147  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11148  * Usually set to TRUE. */
11149  SCIP_Bool local, /**< is constraint only valid locally?
11150  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11151  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11152  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11153  * adds coefficients to this constraint. */
11154  SCIP_Bool dynamic, /**< is constraint subject to aging?
11155  * Usually set to FALSE. Set to TRUE for own cuts which
11156  * are separated as constraints. */
11157  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11158  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11159  )
11160 {
11161  /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
11162  SCIP_CONSHDLR* conshdlr;
11163 
11164  /* find the nonlinear constraint handler */
11165  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11166  if( conshdlr == NULL )
11167  {
11168  SCIPerrorMessage("nonlinear constraint handler not found\n");
11169  return SCIP_PLUGINNOTFOUND;
11170  }
11171 
11172  /* create constraint */
11173  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
11174  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11175 
11176  return SCIP_OKAY;
11177 }
11178 
11179 /** creates and captures a nonlinear constraint with all its constraint flags set to their default values
11180  *
11181  * All flags can be set via SCIPconsSetFLAGNAME-methods.
11182  *
11183  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
11184  *
11185  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11186  */
11188  SCIP* scip, /**< SCIP data structure */
11189  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11190  const char* name, /**< name of constraint */
11191  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11192  SCIP_Real lhs, /**< left hand side of constraint */
11193  SCIP_Real rhs /**< right hand side of constraint */
11194  )
11195 {
11196  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
11197  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11198 
11199  return SCIP_OKAY;
11200 }
11201 
11202 /** creates and captures a quadratic nonlinear constraint
11203  *
11204  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11205  */
11207  SCIP* scip, /**< SCIP data structure */
11208  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11209  const char* name, /**< name of constraint */
11210  int nlinvars, /**< number of linear terms */
11211  SCIP_VAR** linvars, /**< array with variables in linear part */
11212  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11213  int nquadterms, /**< number of quadratic terms */
11214  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11215  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11216  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11217  SCIP_Real lhs, /**< left hand side of quadratic equation */
11218  SCIP_Real rhs, /**< right hand side of quadratic equation */
11219  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11220  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11221  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11222  * Usually set to TRUE. */
11223  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11224  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11225  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11226  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11227  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11228  * Usually set to TRUE. */
11229  SCIP_Bool local, /**< is constraint only valid locally?
11230  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11231  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11232  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11233  * adds coefficients to this constraint. */
11234  SCIP_Bool dynamic, /**< is constraint subject to aging?
11235  * Usually set to FALSE. Set to TRUE for own cuts which
11236  * are separated as constraints. */
11237  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11238  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11239  )
11240 {
11241  SCIP_CONSHDLR* conshdlr;
11242  SCIP_EXPR* expr;
11243 
11244  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
11245  assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
11246 
11247  /* get nonlinear constraint handler */
11248  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11249  if( conshdlr == NULL )
11250  {
11251  SCIPerrorMessage("nonlinear constraint handler not found\n");
11252  return SCIP_PLUGINNOTFOUND;
11253  }
11254 
11255  /* create quadratic expression */
11256  SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
11257  assert(expr != NULL);
11258 
11259  /* create nonlinear constraint */
11260  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
11261  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11262 
11263  /* release quadratic expression (captured by constraint now) */
11264  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11265 
11266  return SCIP_OKAY;
11267 }
11268 
11269 /** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
11270  *
11271  * All flags can be set via SCIPconsSetFLAGNAME-methods.
11272  *
11273  * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
11274  *
11275  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11276  */
11278  SCIP* scip, /**< SCIP data structure */
11279  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11280  const char* name, /**< name of constraint */
11281  int nlinvars, /**< number of linear terms */
11282  SCIP_VAR** linvars, /**< array with variables in linear part */
11283  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11284  int nquadterms, /**< number of quadratic terms */
11285  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11286  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11287  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11288  SCIP_Real lhs, /**< left hand side of quadratic equation */
11289  SCIP_Real rhs /**< right hand side of quadratic equation */
11290  )
11291 {
11292  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11293  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11294 
11295  return SCIP_OKAY;
11296 }
11297 
11298 /** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
11299  *
11300  * \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$
11301  *
11302  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11303  */
11305  SCIP* scip, /**< SCIP data structure */
11306  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11307  const char* name, /**< name of constraint */
11308  int nvars, /**< number of variables on left hand side of constraint (n) */
11309  SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
11310  SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
11311  SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
11312  SCIP_Real constant, /**< constant on left hand side (gamma) */
11313  SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
11314  SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
11315  SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
11316  )
11317 {
11318  SCIP_EXPR* expr;
11319  SCIP_EXPR* lhssum;
11320  SCIP_EXPR* terms[2];
11321  SCIP_Real termcoefs[2];
11322  int i;
11323 
11324  assert(vars != NULL || nvars == 0);
11325 
11326  SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
11327  for( i = 0; i < nvars; ++i )
11328  {
11329  SCIP_EXPR* varexpr;
11330  SCIP_EXPR* powexpr;
11331 
11332  SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
11333  if( offsets != NULL && offsets[i] != 0.0 )
11334  {
11335  SCIP_EXPR* sum;
11336  SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
11337  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
11338  SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
11339  }
11340  else
11341  {
11342  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
11343  }
11344 
11345  SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
11346  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
11347  SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
11348  }
11349 
11350  SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
11351  SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
11352  termcoefs[0] = 1.0;
11353 
11354  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
11355  termcoefs[1] = -rhscoeff;
11356 
11357  SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
11358 
11359  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11360  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11361 
11362  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
11363 
11364  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11365 
11366  return SCIP_OKAY;
11367 }
11368 
11369 /** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
11370  *
11371  * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
11372  *
11373  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11374  */
11376  SCIP* scip, /**< SCIP data structure */
11377  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11378  const char* name, /**< name of constraint */
11379  SCIP_VAR* x, /**< nonlinear variable x in constraint */
11380  SCIP_VAR* z, /**< linear variable z in constraint */
11381  SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
11382  SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
11383  SCIP_Real zcoef, /**< coefficient of z in constraint */
11384  SCIP_Real lhs, /**< left hand side of constraint */
11385  SCIP_Real rhs /**< right hand side of constraint */
11386  )
11387 {
11388  SCIP_EXPR* xexpr;
11389  SCIP_EXPR* terms[2];
11390  SCIP_Real coefs[2];
11391  SCIP_EXPR* sumexpr;
11392 
11393  assert(x != NULL);
11394  assert(z != NULL);
11395 
11396  SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
11397  if( xoffset != 0.0 )
11398  {
11399  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
11400  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
11401 
11402  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11403  }
11404  else
11405  {
11406  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
11407  }
11408  coefs[0] = 1.0;
11409 
11410  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
11411  coefs[1] = zcoef;
11412 
11413  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
11414 
11415  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
11416 
11417  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11418  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11419  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11420  SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
11421 
11422  return SCIP_OKAY;
11423 }
11424 
11425 /** gets tag indicating current local variable bounds */
11427  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11428  )
11429 {
11430  SCIP_CONSHDLRDATA* conshdlrdata;
11431 
11432  assert(conshdlr != NULL);
11433  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11434 
11435  return conshdlrdata->curboundstag;
11436 }
11437 
11438 /** gets the `curboundstag` from the last time where variable bounds were relaxed */
11440  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11441  )
11442 {
11443  SCIP_CONSHDLRDATA* conshdlrdata;
11444 
11445  assert(conshdlr != NULL);
11446  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11447 
11448  return conshdlrdata->lastboundrelax;
11449 }
11450 
11451 /** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
11452  *
11453  * @attention This method is not intended for normal use.
11454  * These tags are maintained by the event handler for variable bound change events.
11455  * This method is used by some unittests.
11456  */
11458  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11459  SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
11460  )
11461 {
11462  SCIP_CONSHDLRDATA* conshdlrdata;
11463 
11464  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11465  assert(conshdlrdata != NULL);
11466 
11467  ++conshdlrdata->curboundstag;
11468  assert(conshdlrdata->curboundstag > 0);
11469 
11470  if( boundrelax )
11471  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
11472 }
11473 
11474 /** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
11476  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11477  )
11478 {
11479  assert(conshdlr != NULL);
11480 
11481  return SCIPconshdlrGetData(conshdlr)->var2expr;
11482 }
11483 
11484 /** processes a rowprep for cut addition and maybe report branchscores */
11486  SCIP* scip, /**< SCIP data structure */
11487  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
11488  SCIP_CONS* cons, /**< nonlinear constraint */
11489  SCIP_EXPR* expr, /**< expression */
11490  SCIP_ROWPREP* rowprep, /**< cut to be added */
11491  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
11492  SCIP_VAR* auxvar, /**< auxiliary variable */
11493  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
11494  SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
11495  SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
11496  SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
11497  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
11498  SCIP_RESULT* result /**< pointer to store the result */
11499  )
11500 {
11501  SCIP_Real cutviol;
11502  SCIP_CONSHDLRDATA* conshdlrdata;
11503  SCIP_Real auxvarvalue = SCIP_INVALID;
11504  SCIP_Bool sepasuccess;
11505  SCIP_Real estimateval = SCIP_INVALID;
11506  SCIP_Real mincutviolation;
11507 
11508  assert(nlhdlr != NULL);
11509  assert(cons != NULL);
11510  assert(expr != NULL);
11511  assert(rowprep != NULL);
11512  assert(auxvar != NULL);
11513  assert(result != NULL);
11514 
11515  /* decide on minimal violation of cut */
11516  if( sol == NULL )
11517  mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
11518  else
11519  mincutviolation = SCIPfeastol(scip);
11520 
11521  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11522  assert(conshdlrdata != NULL);
11523 
11524  sepasuccess = TRUE;
11525 
11526  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
11527  if( cutviol > 0.0 )
11528  {
11529  auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
11530 
11531  /* check whether cut is weak (if f(x) not defined, then it's never weak) */
11532  if( !allowweakcuts && auxvalue != SCIP_INVALID )
11533  {
11534  /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
11535  * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
11536  * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
11537  * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
11538  * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
11539  * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
11540  *
11541  * if we are overestimating, we have z >= c'x-b >= f(x)
11542  * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
11543  * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
11544  * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
11545  *
11546  * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
11547  */
11548  if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11549  ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11550  {
11551  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
11552  "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11553  SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11554  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
11555  sepasuccess = FALSE;
11556  }
11557  }
11558 
11559  /* save estimator value for later, see long comment above why this gives the value for c'x-b */
11560  estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
11561  }
11562  else
11563  {
11564  sepasuccess = FALSE;
11565  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
11566  "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
11567  }
11568 
11569  /* clean up estimator */
11570  if( sepasuccess )
11571  {
11572  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
11573  "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11574  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
11575  SCIPprintRowprep(scip, rowprep, enfologfile); )
11576 
11577  /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
11578  * instead, may even scale them down, that is, scale so that max coef is close to 1
11579  */
11580  if( !allowweakcuts )
11581  {
11582  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
11583 
11584  if( !sepasuccess )
11585  {
11586  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
11587  }
11588  else
11589  {
11590  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
11591  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
11592  "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
11593  if( sepasuccess )
11594  sepasuccess = cutviol > mincutviolation;
11595  }
11596 
11597  if( sepasuccess && auxvalue != SCIP_INVALID )
11598  {
11599  /* check whether cut is weak now
11600  * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
11601  * reconstructing estimateval from cutviol (TODO improve or remove?)
11602  */
11603  SCIP_Real auxvarcoef = 0.0;
11604  int i;
11605 
11606  /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
11607  * it should be...
11608  */
11609  for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
11610  {
11611  if( SCIProwprepGetVars(rowprep)[i] == auxvar )
11612  {
11613  auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
11614  break;
11615  }
11616  }
11617 
11618  if( auxvarcoef == 0.0 ||
11619  (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11620  ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11621  {
11622  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11623  auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
11624  sepasuccess = FALSE;
11625  }
11626  }
11627  }
11628  else
11629  {
11630  /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
11631 
11632  /* if estimate didn't report branchscores explicitly, then consider branching on those children for
11633  * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
11634  */
11635  if( !branchscoresuccess )
11637 
11638  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
11639 
11640  if( !sepasuccess )
11641  {
11642  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
11643  SCIProwprepGetNModifiedVars(rowprep), cutviol); )
11644  }
11645 
11646  /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
11647  * changed
11648  */
11649  if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
11650  {
11651  SCIP_Real violscore;
11652 
11653 #ifdef BRSCORE_ABSVIOL
11654  violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
11655 #else
11656  SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
11657 #endif
11658  SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
11659 
11660  /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
11661  * - were fixed,
11662  * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
11663  * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
11664  * the first case came up again in #3085 and I don't see how to exclude this in the assert,
11665  * so I'm disabling the assert for now
11666  */
11667  /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
11668  strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
11669  }
11670  }
11671  }
11672 
11673  /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
11674  if( sepasuccess )
11675  {
11676  SCIP_ROW* row;
11677 
11678  if( conshdlrdata->branchdualweight > 0.0 )
11679  {
11680  /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
11681  * skip if gap is zero
11682  */
11683  if( auxvalue == SCIP_INVALID )
11684  strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
11685  else if( !SCIPisEQ(scip, auxvalue, estimateval) )
11686  {
11687  char gap[40];
11688  (void) SCIPsnprintf(gap, 40, "_estimategap=%g", REALABS(auxvalue - estimateval));
11689  strcat(SCIProwprepGetName(rowprep), gap);
11690  }
11691  }
11692 
11693  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
11694 
11695  if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
11696  {
11697  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
11698  SCIPgetCutEfficacy(scip, sol, row), SCIPgetSepaMinEfficacy(scip)); )
11699  }
11700  else if( !SCIPisCutApplicable(scip, row) )
11701  {
11702  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
11703  }
11704  else
11705  {
11706  SCIP_Bool infeasible;
11707 
11708  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
11709  SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
11710 
11711  /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
11712  * if we haven't found strong cuts before)
11713  */
11714  SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
11715 
11716  /* mark row as not removable from LP for current node (this can prevent some cycling) */
11717  if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
11718  SCIPmarkRowNotRemovableLocal(scip, row);
11719 
11720  if( infeasible )
11721  {
11722  *result = SCIP_CUTOFF;
11724  }
11725  else
11726  {
11727  *result = SCIP_SEPARATED;
11729  }
11730  }
11731 
11732  SCIP_CALL( SCIPreleaseRow(scip, &row) );
11733  }
11734  else if( branchscoresuccess )
11735  {
11736  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
11737  "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
11738 
11739  /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
11740  * expressions eligible for branching candidate, see enforceConstraints() and branching()
11741  */
11742  *result = SCIP_BRANCHED;
11743  }
11744  else
11745  {
11746  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
11747  "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
11748  " (!)" : ""); )
11749  }
11750 
11751  return SCIP_OKAY;
11752 }
11753 
11754 /** returns whether all nonlinear constraints are assumed to be convex */
11756  SCIP_CONSHDLR* conshdlr
11757  )
11758 {
11759  SCIP_CONSHDLRDATA* conshdlrdata;
11760 
11761  assert(conshdlr != NULL);
11762 
11763  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11764  assert(conshdlrdata != NULL);
11765 
11766  return conshdlrdata->assumeconvex;
11767 }
11768 
11769 /** collects all bilinear terms for a given set of constraints
11770  *
11771  * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
11772  * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
11773  */
11775  SCIP* scip, /**< SCIP data structure */
11776  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11777  SCIP_CONS** conss, /**< nonlinear constraints */
11778  int nconss /**< total number of nonlinear constraints */
11779  )
11780 {
11781  assert(conshdlr != NULL);
11782  assert(conss != NULL || nconss == 0);
11783 
11784  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11785 
11786  return SCIP_OKAY;
11787 }
11788 
11789 /** returns the total number of bilinear terms that are contained in all nonlinear constraints
11790  *
11791  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11792  */
11794  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11795  )
11796 {
11797  SCIP_CONSHDLRDATA* conshdlrdata;
11798 
11799  assert(conshdlr != NULL);
11800 
11801  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11802  assert(conshdlrdata != NULL);
11803 
11804  return conshdlrdata->nbilinterms;
11805 }
11806 
11807 /** returns all bilinear terms that are contained in all nonlinear constraints
11808  *
11809  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11810  * @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.
11811  */
11813  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11814  )
11815 {
11816  SCIP_CONSHDLRDATA* conshdlrdata;
11817 
11818  assert(conshdlr != NULL);
11819 
11820  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11821  assert(conshdlrdata != NULL);
11822 
11823  return conshdlrdata->bilinterms;
11824 }
11825 
11826 /** returns the index of the bilinear term representing the product of the two given variables
11827  *
11828  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11829  * @return The method returns -1 if the variables do not appear bilinearly.
11830  */
11832  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11833  SCIP_VAR* x, /**< first variable */
11834  SCIP_VAR* y /**< second variable */
11835  )
11836 {
11837  SCIP_CONSHDLRDATA* conshdlrdata;
11839  int idx;
11840 
11841  assert(conshdlr != NULL);
11842  assert(x != NULL);
11843  assert(y != NULL);
11844 
11845  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11846  assert(conshdlrdata != NULL);
11847 
11848  if( conshdlrdata->bilinhashtable == NULL )
11849  {
11850  return -1;
11851  }
11852 
11853  /* ensure that x.index <= y.index */
11854  if( SCIPvarCompare(x, y) == 1 )
11855  {
11856  SCIPswapPointers((void**)&x, (void**)&y);
11857  }
11858  assert(SCIPvarCompare(x, y) < 1);
11859 
11860  /* use a new entry to find the image in the bilinear hash table */
11861  entry.x = x;
11862  entry.y = y;
11863  idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
11864  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11865  assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
11866  assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
11867 
11868  return idx;
11869 }
11870 
11871 /** returns the bilinear term that represents the product of two given variables
11872  *
11873  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11874  * @return The method returns NULL if the variables do not appear bilinearly.
11875  */
11877  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11878  SCIP_VAR* x, /**< first variable */
11879  SCIP_VAR* y /**< second variable */
11880  )
11881 {
11882  SCIP_CONSHDLRDATA* conshdlrdata;
11883  int idx;
11884 
11885  assert(conshdlr != NULL);
11886  assert(x != NULL);
11887  assert(y != NULL);
11888 
11889  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11890  assert(conshdlrdata != NULL);
11891 
11892  idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
11893  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11894 
11895  if( idx >= 0 )
11896  {
11897  return &conshdlrdata->bilinterms[idx];
11898  }
11899 
11900  return NULL;
11901 }
11902 
11903 /** evaluates an auxiliary expression for a bilinear term */
11905  SCIP* scip, /**< SCIP data structure */
11906  SCIP_VAR* x, /**< first variable of the bilinear term */
11907  SCIP_VAR* y, /**< second variable of the bilinear term */
11908  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
11909  SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
11910  )
11911 {
11912  assert(scip != NULL);
11913  assert(x != NULL);
11914  assert(y != NULL);
11915  assert(auxexpr != NULL);
11916  assert(auxexpr->auxvar != NULL);
11917 
11918  return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
11919  auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
11920 }
11921 
11922 /** stores the variables of a bilinear term in the data of the constraint handler */
11924  SCIP* scip, /**< SCIP data structure */
11925  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11926  SCIP_VAR* x, /**< first variable */
11927  SCIP_VAR* y, /**< second variable */
11928  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11929  int nlockspos, /**< number of positive expression locks */
11930  int nlocksneg /**< number of negative expression locks */
11931  )
11932 {
11933  SCIP_CONSHDLRDATA* conshdlrdata;
11935  int idx;
11936 
11937  assert(conshdlr != NULL);
11938 
11939  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11940  assert(conshdlrdata != NULL);
11941 
11942  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
11943 
11944  term = &conshdlrdata->bilinterms[idx];
11945  assert(term != NULL);
11946  assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
11947  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) */
11948 
11949  /* store and capture auxiliary variable */
11950  if( auxvar != NULL )
11951  {
11952  term->aux.var = auxvar;
11953  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
11954  }
11955 
11956  return SCIP_OKAY;
11957 }
11958 
11959 /** stores the variables of a bilinear term in the data of the constraint handler */
11961  SCIP* scip, /**< SCIP data structure */
11962  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11963  SCIP_VAR* x, /**< first variable */
11964  SCIP_VAR* y, /**< second variable */
11965  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11966  SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
11967  SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
11968  SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
11969  SCIP_Real cst, /**< constant of the auxiliary expression */
11970  SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
11971  )
11972 {
11973  SCIP_CONSHDLRDATA* conshdlrdata;
11975  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr;
11976  int idx;
11977  int nlockspos;
11978  int nlocksneg;
11979  SCIP_Bool added;
11980 
11981  assert(conshdlr != NULL);
11982 
11983  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11984  assert(conshdlrdata != NULL);
11985 
11986  nlockspos = overestimate ? 1 : 0;
11987  nlocksneg = overestimate ? 0 : 1;
11988 
11989  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
11990 
11991  term = &conshdlrdata->bilinterms[idx];
11992  assert(term != NULL);
11993  assert(SCIPvarCompare(term->x, term->y) < 1);
11994 
11995  if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
11996  {
11997  SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
11998  /* this is the case where we are adding an implicitly defined relation for a product that has already
11999  * been explicitly defined; convert auxvar into an auxexpr */
12000 
12001  /* nothing to do if we aren't allowed to add more than one auxexpr per term */
12002  if( conshdlrdata->bilinmaxnauxexprs <= 1 )
12003  return SCIP_OKAY;
12004 
12005  SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
12006  auxvarexpr->cst = 0.0;
12007  auxvarexpr->coefs[0] = 1.0;
12008  auxvarexpr->coefs[1] = 0.0;
12009  auxvarexpr->coefs[2] = 0.0;
12010  auxvarexpr->auxvar = term->aux.var;
12011  auxvarexpr->underestimate = term->nlocksneg > 0;
12012  auxvarexpr->overestimate = term->nlockspos > 0;
12013 
12014  /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
12015  term->aux.exprs = NULL;
12016 
12017  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
12018 
12019  /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
12020  assert(added);
12021  }
12022 
12023  /* create and add auxexpr */
12024  SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
12025  auxexpr->underestimate = !overestimate;
12026  auxexpr->overestimate = overestimate;
12027  auxexpr->auxvar = auxvar;
12028  auxexpr->coefs[0] = coefaux;
12029  if( term->x == x )
12030  {
12031  assert(term->y == y);
12032  auxexpr->coefs[1] = coefx;
12033  auxexpr->coefs[2] = coefy;
12034  }
12035  else
12036  {
12037  assert(term->x == y);
12038  assert(term->y == x);
12039  auxexpr->coefs[1] = coefy;
12040  auxexpr->coefs[2] = coefx;
12041  }
12042  auxexpr->cst = cst;
12043  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
12044 
12045  if( !added )
12046  {
12047  SCIPfreeBlockMemory(scip, &auxexpr);
12048  }
12049  else if( auxvar != NULL )
12050  { /* capture auxiliary variable */
12051  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
12052  }
12053 
12054  return SCIP_OKAY;
12055 }
12056 
12057 /* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
12059  SCIP* scip, /**< SCIP data structure */
12060  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12061  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
12062  SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
12063  void* fundata, /**< data for function evaluation (can be NULL) */
12064  SCIP_Real* xstar, /**< point to be separated */
12065  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
12066  int nallvars, /**< half of the length of box */
12067  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
12068  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
12069  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
12070  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
12071  )
12072 {
12073  SCIP_Real* corner;
12074  SCIP_Real* funvals;
12075  int* nonfixedpos;
12076  SCIP_Real maxfaceterror;
12077  int nvars; /* number of nonfixed variables */
12078  unsigned int ncorners;
12079  unsigned int i;
12080  int j;
12081 
12082  assert(scip != NULL);
12083  assert(conshdlr != NULL);
12084  assert(function != NULL);
12085  assert(xstar != NULL);
12086  assert(box != NULL);
12087  assert(success != NULL);
12088  assert(facetcoefs != NULL);
12089  assert(facetconstant != NULL);
12090 
12091  *success = FALSE;
12092 
12093  /* identify fixed variables */
12094  SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
12095  nvars = 0;
12096  for( j = 0; j < nallvars; ++j )
12097  {
12098  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12099  continue;
12100  nonfixedpos[nvars] = j;
12101  nvars++;
12102  }
12103 
12104  /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
12105  * if too many variables are not fixed, then we do nothing currently
12106  */
12107  if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
12108  {
12109  SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
12110  SCIPfreeBufferArray(scip, &nonfixedpos);
12111  return SCIP_OKAY;
12112  }
12113 
12114  /* compute f(v^i) for each corner v^i of [l,u] */
12115  ncorners = POWEROFTWO(nvars);
12116  SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
12117  SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
12118  for( j = 0; j < nallvars; ++j )
12119  {
12120  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12121  corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
12122  }
12123  for( i = 0; i < ncorners; ++i )
12124  {
12125  SCIPdebugMsg(scip, "corner %u: ", i);
12126  for( j = 0; j < nvars; ++j )
12127  {
12128  int varpos = nonfixedpos[j];
12129  /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
12130  * we check this by shifting i for j positions to the right and checking whether the last bit is set
12131  */
12132  if( (i >> j) & 0x1 )
12133  corner[varpos] = box[2 * varpos + 1]; /* ub of var */
12134  else
12135  corner[varpos] = box[2 * varpos ]; /* lb of var */
12136  SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
12137  assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
12138  }
12139 
12140  funvals[i] = function(corner, nallvars, fundata);
12141 
12142  SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
12143 
12144  if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
12145  {
12146  SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
12147  goto CLEANUP;
12148  }
12149  }
12150 
12151  /* clear coefs array; below we only fill in coefs for nonfixed variables */
12152  BMSclearMemoryArray(facetcoefs, nallvars);
12153 
12154  if( nvars == 1 )
12155  {
12156  SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
12157 
12158  /* check whether target has been missed */
12159  if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
12160  {
12161  SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
12162  *success = FALSE;
12163  }
12164  }
12165  else if( nvars == 2 )
12166  {
12167  int idx1 = nonfixedpos[0];
12168  int idx2 = nonfixedpos[1];
12169  SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
12170  SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
12171  SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
12172  SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
12173  SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
12174  SCIP_Real coefs[2] = { 0.0, 0.0 };
12175 
12176  SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
12177 
12178  facetcoefs[idx1] = coefs[0];
12179  facetcoefs[idx2] = coefs[1];
12180  }
12181  else
12182  {
12183  SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
12184  }
12185  if( !*success )
12186  {
12187  SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
12188  goto CLEANUP;
12189  }
12190 
12191  /*
12192  * check and adjust facet with the algorithm of Rikun et al.
12193  */
12194 
12195  maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
12196 
12197  /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
12198  if( maxfaceterror > 0.0 )
12199  {
12200  SCIP_CONSHDLRDATA* conshdlrdata;
12201  SCIP_Real midval;
12202  SCIP_Real feastol;
12203 
12204  feastol = SCIPgetStage(scip) == SCIP_STAGE_SOLVING ? SCIPgetLPFeastol(scip) : SCIPfeastol(scip);
12205 
12206  /* evaluate function in middle point to get some idea for a scaling */
12207  for( j = 0; j < nvars; ++j )
12208  corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
12209  midval = function(corner, nallvars, fundata);
12210  if( midval == SCIP_INVALID )
12211  midval = 1.0;
12212 
12213  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12214  assert(conshdlrdata != NULL);
12215 
12216  /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
12217  if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
12218  {
12219  SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
12220  *success = FALSE;
12221  goto CLEANUP;
12222  }
12223 
12224  SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
12225 
12226  if( overestimate )
12227  *facetconstant += maxfaceterror;
12228  else
12229  *facetconstant -= maxfaceterror;
12230  }
12231 
12232  /* if we made it until here, then we have a nice facet */
12233  assert(*success);
12234 
12235 CLEANUP:
12236  /* free allocated memory */
12237  SCIPfreeBufferArray(scip, &corner);
12238  SCIPfreeBufferArray(scip, &funvals);
12239  SCIPfreeBufferArray(scip, &nonfixedpos);
12240 
12241  return SCIP_OKAY;
12242 }
12243 
12244 /*
12245  * constraint specific interface methods
12246  */
12247 
12248 /** returns the expression of the given nonlinear constraint */
12250  SCIP_CONS* cons /**< constraint data */
12251  )
12252 {
12253  SCIP_CONSDATA* consdata;
12254 
12255  assert(cons != NULL);
12256  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12257 
12258  consdata = SCIPconsGetData(cons);
12259  assert(consdata != NULL);
12260 
12261  return consdata->expr;
12262 }
12263 
12264 /** gets the left hand side of a nonlinear constraint */
12266  SCIP_CONS* cons /**< constraint data */
12267  )
12268 {
12269  SCIP_CONSDATA* consdata;
12270 
12271  assert(cons != NULL);
12272  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12273 
12274  consdata = SCIPconsGetData(cons);
12275  assert(consdata != NULL);
12276 
12277  return consdata->lhs;
12278 }
12279 
12280 /** gets the right hand side of a nonlinear constraint */
12282  SCIP_CONS* cons /**< constraint data */
12283  )
12284 {
12285  SCIP_CONSDATA* consdata;
12286 
12287  assert(cons != NULL);
12288  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12289 
12290  consdata = SCIPconsGetData(cons);
12291  assert(consdata != NULL);
12292 
12293  return consdata->rhs;
12294 }
12295 
12296 /** gets the nonlinear constraint as a nonlinear row representation. */
12298  SCIP* scip, /**< SCIP data structure */
12299  SCIP_CONS* cons, /**< constraint */
12300  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
12301  )
12302 {
12303  SCIP_CONSDATA* consdata;
12304 
12305  assert(cons != NULL);
12306  assert(nlrow != NULL);
12307  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12308 
12309  consdata = SCIPconsGetData(cons);
12310  assert(consdata != NULL);
12311 
12312  if( consdata->nlrow == NULL )
12313  {
12314  SCIP_CALL( createNlRow(scip, cons) );
12315  }
12316  assert(consdata->nlrow != NULL);
12317  *nlrow = consdata->nlrow;
12318 
12319  return SCIP_OKAY;
12320 }
12321 
12322 /** returns the curvature of the expression of a given nonlinear constraint
12323  *
12324  * @note The curvature information is computed during CONSINITSOL.
12325  */
12327  SCIP_CONS* cons /**< constraint data */
12328  )
12329 {
12330  SCIP_CONSDATA* consdata;
12331 
12332  assert(cons != NULL);
12333  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12334 
12335  consdata = SCIPconsGetData(cons);
12336  assert(consdata != NULL);
12337 
12338  return consdata->curv;
12339 }
12340 
12341 /** checks whether expression of constraint can be represented as quadratic form
12342  *
12343  * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
12344  * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
12345  * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
12346  */
12348  SCIP* scip, /**< SCIP data structure */
12349  SCIP_CONS* cons, /**< constraint data */
12350  SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
12351  )
12352 {
12353  SCIP_CONSDATA* consdata;
12354 
12355  assert(scip != NULL);
12356  assert(cons != NULL);
12357  assert(isquadratic != NULL);
12358  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12359 
12360  consdata = SCIPconsGetData(cons);
12361  assert(consdata != NULL);
12362  assert(consdata->expr != NULL);
12363 
12364  /* check whether constraint expression is quadratic in extended formulation */
12365  SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
12366 
12367  /* if not quadratic in non-extended formulation, then do indicate quadratic */
12368  if( *isquadratic )
12369  *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
12370 
12371  return SCIP_OKAY;
12372 }
12373 
12374 /** changes left-hand-side of a nonlinear constraint
12375  *
12376  * @attention This method can only be called in the problem stage.
12377  */
12379  SCIP* scip, /**< SCIP data structure */
12380  SCIP_CONS* cons, /**< constraint data */
12381  SCIP_Real lhs /**< new left-hand-side */
12382  )
12383 {
12384  SCIP_CONSDATA* consdata;
12385 
12386  assert(scip != NULL);
12387  assert(cons != NULL);
12388  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12389 
12390  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12391  {
12392  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12393  return SCIP_INVALIDCALL;
12394  }
12395 
12396  /* we should have an original constraint */
12397  assert(SCIPconsIsOriginal(cons));
12398 
12399  consdata = SCIPconsGetData(cons);
12400  assert(consdata != NULL);
12401 
12402  if( consdata->lhs == lhs )
12403  return SCIP_OKAY;
12404 
12405  consdata->lhs = lhs;
12406 
12407  /* not sure we care about any of these flags for original constraints */
12408  consdata->ispropagated = FALSE;
12409 
12410  return SCIP_OKAY;
12411 }
12412 
12413 /** changes right-hand-side of a nonlinear constraint
12414  *
12415  * @attention This method can only be called in the problem stage.
12416  */
12418  SCIP* scip, /**< SCIP data structure */
12419  SCIP_CONS* cons, /**< constraint data */
12420  SCIP_Real rhs /**< new right-hand-side */
12421  )
12422 {
12423  SCIP_CONSDATA* consdata;
12424 
12425  assert(scip != NULL);
12426  assert(cons != NULL);
12427  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12428 
12429  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12430  {
12431  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12432  return SCIP_INVALIDCALL;
12433  }
12434 
12435  /* we should have an original constraint */
12436  assert(SCIPconsIsOriginal(cons));
12437 
12438  consdata = SCIPconsGetData(cons);
12439  assert(consdata != NULL);
12440 
12441  if( consdata->rhs == rhs )
12442  return SCIP_OKAY;
12443 
12444  consdata->rhs = rhs;
12445 
12446  /* not sure we care about any of these flags for original constraints */
12447  consdata->ispropagated = FALSE;
12448 
12449  return SCIP_OKAY;
12450 }
12451 
12452 /** changes expression of a nonlinear constraint
12453  *
12454  * @attention This method can only be called in the problem stage.
12455  */
12457  SCIP* scip, /**< SCIP data structure */
12458  SCIP_CONS* cons, /**< constraint data */
12459  SCIP_EXPR* expr /**< new expression */
12460  )
12461 {
12462  SCIP_CONSHDLR* conshdlr;
12463  SCIP_CONSDATA* consdata;
12464 
12465  assert(scip != NULL);
12466  assert(cons != NULL);
12467  assert(expr != NULL);
12468 
12469  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12470  {
12471  SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
12472  return SCIP_INVALIDCALL;
12473  }
12474 
12475  /* we should have an original constraint */
12476  assert(SCIPconsIsOriginal(cons));
12477 
12478  conshdlr = SCIPconsGetHdlr(cons);
12479  assert(conshdlr != NULL);
12480  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12481 
12482  consdata = SCIPconsGetData(cons);
12483  assert(consdata != NULL);
12484  assert(consdata->expr != NULL);
12485 
12486  /* we should not have collected additional data for the expr
12487  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12488  */
12489  assert(consdata->nvarexprs == 0);
12490  assert(consdata->varexprs == NULL);
12491  assert(!consdata->catchedevents);
12492 
12493  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
12494 
12495  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12496  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12497 
12498  /* not sure we care about any of these flags for original constraints */
12499  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
12500  consdata->issimplified = FALSE;
12501  consdata->ispropagated = FALSE;
12502 
12503  return SCIP_OKAY;
12504 }
12505 
12506 /** adds coef * var to nonlinear constraint
12507  *
12508  * @attention This method can only be called in the problem stage.
12509  */
12511  SCIP* scip, /**< SCIP data structure */
12512  SCIP_CONS* cons, /**< constraint data */
12513  SCIP_VAR* var, /**< variable */
12514  SCIP_Real coef /**< coefficient */
12515  )
12516 {
12517  SCIP_CONSHDLR* conshdlr;
12518  SCIP_CONSDATA* consdata;
12519  SCIP_EXPR* varexpr;
12520 
12521  assert(scip != NULL);
12522  assert(cons != NULL);
12523 
12524  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12525  {
12526  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12527  return SCIP_INVALIDCALL;
12528  }
12529 
12530  /* we should have an original constraint */
12531  assert(SCIPconsIsOriginal(cons));
12532 
12533  if( coef == 0.0 )
12534  return SCIP_OKAY;
12535 
12536  conshdlr = SCIPconsGetHdlr(cons);
12537  assert(conshdlr != NULL);
12538  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12539 
12540  consdata = SCIPconsGetData(cons);
12541  assert(consdata != NULL);
12542  assert(consdata->expr != NULL);
12543 
12544  /* we should not have collected additional data for it
12545  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12546  */
12547  assert(consdata->nvarexprs == 0);
12548  assert(consdata->varexprs == NULL);
12549  assert(!consdata->catchedevents);
12550 
12551  SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
12552 
12553  /* append to sum, if consdata->expr is sum and not used anywhere else */
12554  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12555  {
12556  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
12557  }
12558  else
12559  {
12560  /* create new expression = 1 * consdata->expr + coef * var */
12561  SCIP_EXPR* children[2] = { consdata->expr, varexpr };
12562  SCIP_Real coefs[2] = { 1.0, coef };
12563 
12564  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12565 
12566  /* release old root expr */
12567  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12568  }
12569 
12570  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12571 
12572  /* not sure we care about any of these flags for original constraints */
12573  consdata->issimplified = FALSE;
12574  consdata->ispropagated = FALSE;
12575 
12576  return SCIP_OKAY;
12577 }
12578 
12579 /** adds coef * expr to nonlinear constraint
12580  *
12581  * @attention This method can only be called in the problem stage.
12582  */
12584  SCIP* scip, /**< SCIP data structure */
12585  SCIP_CONS* cons, /**< nonlinear constraint */
12586  SCIP_EXPR* expr, /**< expression */
12587  SCIP_Real coef /**< coefficient */
12588  )
12589 {
12590  SCIP_CONSHDLR* conshdlr;
12591  SCIP_CONSDATA* consdata;
12592  SCIP_EXPR* exprowned;
12593 
12594  assert(scip != NULL);
12595  assert(cons != NULL);
12596 
12597  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12598  {
12599  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12600  return SCIP_INVALIDCALL;
12601  }
12602 
12603  /* we should have an original constraint */
12604  assert(SCIPconsIsOriginal(cons));
12605 
12606  if( coef == 0.0 )
12607  return SCIP_OKAY;
12608 
12609  conshdlr = SCIPconsGetHdlr(cons);
12610  assert(conshdlr != NULL);
12611  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12612 
12613  consdata = SCIPconsGetData(cons);
12614  assert(consdata != NULL);
12615  assert(consdata->expr != NULL);
12616 
12617  /* we should not have collected additional data for it
12618  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12619  */
12620  assert(consdata->nvarexprs == 0);
12621  assert(consdata->varexprs == NULL);
12622  assert(!consdata->catchedevents);
12623 
12624  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12625  SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12626 
12627  /* append to sum, if consdata->expr is sum and not used anywhere else */
12628  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12629  {
12630  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
12631  }
12632  else
12633  {
12634  /* create new expression = 1 * consdata->expr + coef * var */
12635  SCIP_EXPR* children[2] = { consdata->expr, exprowned };
12636  SCIP_Real coefs[2] = { 1.0, coef };
12637 
12638  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12639 
12640  /* release old root expr */
12641  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12642  }
12643 
12644  SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
12645 
12646  /* not sure we care about any of these flags for original constraints */
12647  consdata->issimplified = FALSE;
12648  consdata->ispropagated = FALSE;
12649 
12650  return SCIP_OKAY;
12651 }
12652 
12653 /** gets absolute violation of nonlinear constraint
12654  *
12655  * This function evaluates the constraints in the given solution.
12656  *
12657  * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
12658  */
12660  SCIP* scip, /**< SCIP data structure */
12661  SCIP_CONS* cons, /**< constraint */
12662  SCIP_SOL* sol, /**< solution to check */
12663  SCIP_Real* viol /**< buffer to store computed violation */
12664  )
12665 {
12666  assert(cons != NULL);
12667  assert(viol != NULL);
12668 
12669  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12670  *viol = getConsAbsViolation(cons);
12671 
12672  return SCIP_OKAY;
12673 }
12674 
12675 /** gets scaled violation of nonlinear constraint
12676  *
12677  * This function evaluates the constraints in the given solution.
12678  *
12679  * The scaling that is applied to the absolute violation of the constraint
12680  * depends on the setting of parameter constraints/nonlinear/violscale.
12681  */
12683  SCIP* scip, /**< SCIP data structure */
12684  SCIP_CONS* cons, /**< constraint */
12685  SCIP_SOL* sol, /**< solution to check */
12686  SCIP_Real* viol /**< buffer to store computed violation */
12687  )
12688 {
12689  assert(cons != NULL);
12690  assert(viol != NULL);
12691 
12692  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12693  SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
12694 
12695  return SCIP_OKAY;
12696 }
12697 
12698 /** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
12700  SCIP* scip, /**< SCIP data structure */
12701  SCIP_CONS* cons, /**< nonlinear constraint */
12702  SCIP_VAR** var, /**< pointer to store the variable */
12703  SCIP_Real* coef /**< pointer to store the coefficient */
12704  )
12705 {
12706  SCIP_CONSDATA* consdata;
12707 
12708  assert(cons != NULL);
12709  assert(var != NULL);
12710  assert(coef != NULL);
12711 
12712  /* check for a linear variable that can be increased or decreased without harming feasibility */
12713  findUnlockedLinearVar(scip, cons);
12714 
12715  consdata = SCIPconsGetData(cons);
12716  assert(consdata != NULL);
12717 
12718  *var = consdata->linvardecr;
12719  *coef = consdata->linvardecrcoef;
12720 }
12721 
12722 /** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
12724  SCIP* scip, /**< SCIP data structure */
12725  SCIP_CONS* cons, /**< nonlinear constraint */
12726  SCIP_VAR** var, /**< pointer to store the variable */
12727  SCIP_Real* coef /**< pointer to store the coefficient */
12728  )
12729 {
12730  SCIP_CONSDATA* consdata;
12731 
12732  assert(cons != NULL);
12733  assert(var != NULL);
12734  assert(coef != NULL);
12735 
12736  /* check for a linear variable that can be increased or decreased without harming feasibility */
12737  findUnlockedLinearVar(scip, cons);
12738 
12739  consdata = SCIPconsGetData(cons);
12740  assert(consdata != NULL);
12741 
12742  *var = consdata->linvarincr;
12743  *coef = consdata->linvarincrcoef;
12744 }
12745 
12746 
12747 /*
12748  * Methods for Expressions in Nonlinear Constraints
12749  */
12750 
12751 /** returns the number of positive rounding locks of an expression */
12753  SCIP_EXPR* expr /**< expression */
12754  )
12755 {
12756  assert(expr != NULL);
12757  assert(SCIPexprGetOwnerData(expr) != NULL);
12758 
12759  return SCIPexprGetOwnerData(expr)->nlockspos;
12760 }
12761 
12762 /** returns the number of negative rounding locks of an expression */
12764  SCIP_EXPR* expr /**< expression */
12765  )
12766 {
12767  assert(expr != NULL);
12768  assert(SCIPexprGetOwnerData(expr) != NULL);
12769 
12770  return SCIPexprGetOwnerData(expr)->nlocksneg;
12771 }
12772 
12773 /** returns the variable used for linearizing a given expression (return value might be NULL)
12774  *
12775  * @note for variable expression it returns the corresponding variable
12776  */
12778  SCIP_EXPR* expr /**< expression */
12779  )
12780 {
12781  SCIP_EXPR_OWNERDATA* ownerdata;
12782 
12783  assert(expr != NULL);
12784 
12785  ownerdata = SCIPexprGetOwnerData(expr);
12786  assert(ownerdata != NULL);
12787 
12788  return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
12789 }
12790 
12791 /** returns the number of enforcements for an expression */
12793  SCIP_EXPR* expr /**< expression */
12794  )
12795 {
12796  assert(expr != NULL);
12797  assert(SCIPexprGetOwnerData(expr) != NULL);
12798 
12799  return SCIPexprGetOwnerData(expr)->nenfos;
12800 }
12801 
12802 /** returns the data for one of the enforcements of an expression */
12804  SCIP_EXPR* expr, /**< expression */
12805  int idx, /**< position of enforcement in enfos array */
12806  SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
12807  SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
12808  SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
12809  SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
12810  SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
12811  SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
12812  )
12813 {
12814  SCIP_EXPR_OWNERDATA* ownerdata;
12815 
12816  assert(expr != NULL);
12817 
12818  ownerdata = SCIPexprGetOwnerData(expr);
12819  assert(ownerdata != NULL);
12820  assert(idx >= 0);
12821  assert(idx < ownerdata->nenfos);
12822  assert(ownerdata->enfos[idx] != NULL);
12823  assert(nlhdlr != NULL);
12824 
12825  *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
12826 
12827  if( nlhdlrexprdata != NULL )
12828  *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
12829 
12830  if( nlhdlrparticipation != NULL )
12831  *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
12832 
12833  if( sepabelowusesactivity != NULL )
12834  *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
12835 
12836  if( sepaaboveusesactivity != NULL )
12837  *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
12838 
12839  if( auxvalue != NULL )
12840  *auxvalue = ownerdata->enfos[idx]->auxvalue;
12841 }
12842 
12843 /** sets the auxiliary value of expression for one of the enforcements of an expression */
12845  SCIP_EXPR* expr, /**< expression */
12846  int idx, /**< position of enforcement in enfos array */
12847  SCIP_Real auxvalue /**< the new value of auxval */
12848  )
12849 {
12850  SCIP_EXPR_OWNERDATA* ownerdata;
12851 
12852  assert(expr != NULL);
12853 
12854  ownerdata = SCIPexprGetOwnerData(expr);
12855  assert(ownerdata != NULL);
12856 
12857  assert(idx >= 0);
12858  assert(idx < ownerdata->nenfos);
12859  assert(ownerdata->enfos[idx] != NULL);
12860 
12861  ownerdata->enfos[idx]->auxvalue = auxvalue;
12862 }
12863 
12864 /** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
12865  *
12866  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12867  */
12869  SCIP_EXPR* expr /**< expression */
12870  )
12871 {
12872  assert(expr != NULL);
12873  assert(SCIPexprGetOwnerData(expr) != NULL);
12874 
12875  return SCIPexprGetOwnerData(expr)->nactivityusesprop;
12876 }
12877 
12878 /** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
12879  *
12880  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12881  */
12883  SCIP_EXPR* expr /**< expression */
12884  )
12885 {
12886  assert(expr != NULL);
12887  assert(SCIPexprGetOwnerData(expr) != NULL);
12888 
12889  return SCIPexprGetOwnerData(expr)->nactivityusessepa;
12890 }
12891 
12892 /** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
12893  *
12894  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12895  */
12896 unsigned int SCIPgetExprNAuxvarUsesNonlinear(
12897  SCIP_EXPR* expr /**< expression */
12898  )
12899 {
12900  assert(expr != NULL);
12901  assert(SCIPexprGetOwnerData(expr) != NULL);
12902 
12903  return SCIPexprGetOwnerData(expr)->nauxvaruses;
12904 }
12905 
12906 /** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
12907  *
12908  * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
12909  * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
12910  * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
12911  * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
12912  * and also increments this count for all variables in the expression.
12913  *
12914  * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
12915  * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
12916  * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
12917  * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
12918  */
12920  SCIP* scip, /**< SCIP data structure */
12921  SCIP_EXPR* expr, /**< expression */
12922  SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
12923  SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
12924  SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
12925  SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
12926  )
12927 {
12928  SCIP_EXPR_OWNERDATA* ownerdata;
12929 
12930  assert(expr != NULL);
12931 
12932  ownerdata = SCIPexprGetOwnerData(expr);
12933  assert(ownerdata != NULL);
12934 
12935  /* do not store auxvar request for variable expressions */
12936  if( useauxvar && SCIPisExprVar(scip, expr) )
12937  useauxvar = FALSE;
12938 
12939  if( ownerdata->nenfos >= 0 &&
12940  ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
12941  (ownerdata->nauxvaruses == 0 && useauxvar)
12942  ) )
12943  {
12944  /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
12945  * we require additional enforcement methods, that is,
12946  * - activity of expr was not used before but will be used now, or
12947  * - auxiliary variable of expr was not required before but will be used now
12948  */
12949  SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
12950  }
12951 
12952  if( useauxvar )
12953  ++ownerdata->nauxvaruses;
12954 
12955  if( useactivityforprop )
12956  ++ownerdata->nactivityusesprop;
12957 
12958  if( useactivityforsepabelow || useactivityforsepaabove )
12959  ++ownerdata->nactivityusessepa;
12960 
12961  /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
12962  * information is used in detectNlhdlr()
12963  */
12964  if( useactivityforsepabelow )
12965  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
12966  if( useactivityforsepaabove )
12967  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
12968 
12969  if( useactivityforprop )
12970  {
12971  /* if activity will be used for propagation, then make sure there is a valid activity
12972  * this way, we can do a reversepropcall after detectNlhdlr
12973  */
12974  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
12975  }
12976 
12977  /* increase the nactivityusedsepa counter for all variables used in the given expression */
12978  if(( useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
12979  {
12980  SCIP_EXPRITER* it;
12981 
12982  /* create and initialize iterator */
12983  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
12985 
12986  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
12987  if( SCIPisExprVar(scip, expr) )
12988  ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
12989 
12990  /* free iterator */
12991  SCIPfreeExpriter(&it);
12992  }
12993 
12994  return SCIP_OKAY;
12995 }
12996 
12997 /** computes absolute violation for auxvar relation in an expression w.r.t. original variables
12998  *
12999  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
13000  * Assume that f(x) is associated with auxiliary variable z.
13001  *
13002  * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
13003  * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
13004  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
13005  *
13006  * If necessary, f is evaluated in the given solution. If that fails (domain error),
13007  * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
13008  */
13010  SCIP* scip, /**< SCIP data structure */
13011  SCIP_EXPR* expr, /**< expression */
13012  SCIP_SOL* sol, /**< solution */
13013  SCIP_Longint soltag, /**< tag of solution */
13014  SCIP_Real* viol, /**< buffer to store computed violation */
13015  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
13016  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
13017  )
13018 {
13019  assert(scip != NULL);
13020  assert(expr != NULL);
13021  assert(viol != NULL);
13022 
13023  /* make sure expression has been evaluated */
13024  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
13025 
13026  /* get violation from internal method */
13027  *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
13028 
13029  return SCIP_OKAY;
13030 }
13031 
13032 /** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
13033  *
13034  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13035  * Assume that f(w) is associated with auxiliary variable z.
13036  *
13037  * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
13038  * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
13039  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
13040  *
13041  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13042  * both `violover` and `violunder` are set to TRUE.
13043  */
13045  SCIP* scip, /**< SCIP data structure */
13046  SCIP_EXPR* expr, /**< expression */
13047  SCIP_Real auxvalue, /**< the value of f(w) */
13048  SCIP_SOL* sol, /**< solution that has been evaluated */
13049  SCIP_Real* viol, /**< buffer to store computed violation */
13050  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13051  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13052  )
13053 {
13054  assert(scip != NULL);
13055  assert(expr != NULL);
13056  assert(viol != NULL);
13057 
13058  /* get violation from internal method */
13059  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13060 
13061  return SCIP_OKAY;
13062 }
13063 
13064 
13065 /** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
13066  *
13067  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13068  * Assume that f(w) is associated with auxiliary variable z.
13069  *
13070  * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
13071  * the absolute violation divided by max(1,|f(w)|).
13072  *
13073  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13074  * both `violover` and `violunder` are set to TRUE.
13075  */
13077  SCIP* scip, /**< SCIP data structure */
13078  SCIP_EXPR* expr, /**< expression */
13079  SCIP_Real auxvalue, /**< the value of f(w) */
13080  SCIP_SOL* sol, /**< solution that has been evaluated */
13081  SCIP_Real* viol, /**< buffer to store computed violation */
13082  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13083  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13084  )
13085 {
13086  assert(scip != NULL);
13087  assert(expr != NULL);
13088  assert(viol != NULL);
13089 
13090  /* get violation from internal method */
13091  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13092 
13093  if( !SCIPisInfinity(scip, *viol) )
13094  {
13095  assert(auxvalue != SCIP_INVALID);
13096  /* TODO maybe we should rather use max(eps,|auxvalue|)? */
13097  *viol /= MAX(1.0, REALABS(auxvalue));
13098  }
13099 
13100  return SCIP_OKAY;
13101 }
13102 
13103 /** returns bounds on the expression
13104  *
13105  * This gives an intersection of bounds from
13106  * - activity calculation (SCIPexprGetActivity()), if valid,
13107  * - auxiliary variable, if present,
13108  * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
13109  *
13110  * @note The returned interval can be empty!
13111  */
13113  SCIP* scip, /**< SCIP data structure */
13114  SCIP_EXPR* expr /**< expression */
13115  )
13116 {
13117  SCIP_EXPR_OWNERDATA* ownerdata;
13118  SCIP_CONSHDLRDATA* conshdlrdata;
13119  SCIP_INTERVAL bounds;
13120 
13121  assert(scip != NULL);
13122  assert(expr != NULL);
13123 
13124  ownerdata = SCIPexprGetOwnerData(expr);
13125  assert(ownerdata != NULL);
13126 
13127  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13128  assert(conshdlrdata != NULL);
13129 
13130  /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
13131 
13132  /* start with propbounds if they belong to current propagation */
13133  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13134  {
13135  bounds = ownerdata->propbounds;
13136  /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
13137  }
13138  else
13140 
13141  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
13142  {
13143  /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
13144  /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
13145  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), bounds);
13146  }
13147 
13148  if( ownerdata->auxvar != NULL )
13149  {
13150  /* apply auxiliary variable bounds to bounds */
13151  SCIP_INTERVAL auxvarbounds;
13152 
13153  auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
13154  /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
13155  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
13156  }
13157 
13158  /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
13159 
13160  return bounds;
13161 }
13162 
13163 /** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
13164  * corresponding (auxiliary) variable (if any)
13165  *
13166  * @attention this function should only be called during domain propagation in cons_nonlinear
13167  */
13169  SCIP* scip, /**< SCIP data structure */
13170  SCIP_EXPR* expr, /**< expression to be tightened */
13171  SCIP_INTERVAL newbounds, /**< new bounds for the expression */
13172  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
13173  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
13174  )
13175 {
13176  SCIP_EXPR_OWNERDATA* ownerdata;
13177  SCIP_CONSHDLRDATA* conshdlrdata;
13178 
13179  assert(scip != NULL);
13180  assert(expr != NULL);
13181  assert(cutoff != NULL);
13182 
13183  ownerdata = SCIPexprGetOwnerData(expr);
13184  assert(ownerdata != NULL);
13185  assert(ownerdata->conshdlr != NULL);
13186 
13187  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13188  assert(conshdlrdata != NULL);
13189 
13190  /* the code below assumes that current activity is valid
13191  * if it turns out that we cannot ensure that, then we should change code
13192  */
13193  assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13195 
13196  *cutoff = FALSE;
13197 
13198 #ifdef DEBUG_PROP
13199  SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
13200  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
13201  SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
13202 #endif
13203 
13204  if( SCIPexprIsIntegral(expr) )
13205  {
13206  /* apply integrality to new bounds
13207  * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
13208  */
13209  if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
13210  newbounds.inf = SCIPceil(scip, newbounds.inf);
13211  if( newbounds.sup < SCIP_INTERVAL_INFINITY )
13212  newbounds.sup = SCIPfloor(scip, newbounds.sup);
13213 #ifdef DEBUG_PROP
13214  SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
13215 #endif
13216  }
13217 
13219  {
13220  SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
13221 
13222  *cutoff = TRUE;
13223  return SCIP_OKAY;
13224  }
13225 
13226  /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
13227  if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
13228  {
13229  SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
13230 
13231  *cutoff = TRUE;
13232  return SCIP_OKAY;
13233  }
13234 
13235  /* tighten newbounds w.r.t. existing expr->propbounds or activity */
13236  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13237  {
13238  /* if already having propbounds in expr, then tighten newbounds by propbounds */
13239  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
13240  }
13241  else
13242  {
13243  /* first time we have propbounds for expr in this propagation rounds:
13244  * intersect with activity (though don't let it become empty if very close intervals)
13245  */
13246  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
13247  }
13248 #ifdef DEBUG_PROP
13249  SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
13250 #endif
13251 
13252  /* check if the new bounds lead to an empty interval */
13254  {
13255  SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
13256 
13257  *cutoff = TRUE;
13258  return SCIP_OKAY;
13259  }
13260 
13261  /* if expr is not constant or variable, then store newbounds in expr->propbounds
13262  * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
13263  * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
13264  */
13265  if( SCIPexprGetNChildren(expr) > 0 )
13266  {
13267  ownerdata->propbounds = newbounds;
13268  ownerdata->propboundstag = conshdlrdata->curpropboundstag;
13269  }
13270 
13271  /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
13272  * propagation or update of auxvar bounds
13273  * TODO? if we first had a considerable tightening and then only get small tightenings under the same
13274  * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
13275  * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
13276  * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
13277  * one or should we not even update propbounds to newbounds if the update is small?
13278  */
13279  if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
13280  {
13281 #ifdef DEBUG_PROP
13282  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);
13283 #endif
13284  return SCIP_OKAY;
13285  }
13286 
13287  if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
13288  {
13289  /* add expression to propagation queue if not there yet and not var or constant and
13290  * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
13291  */
13292 #ifdef DEBUG_PROP
13293  SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
13294 #endif
13295  SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
13296  ownerdata->inpropqueue = TRUE;
13297  }
13298 
13299  /* update bounds on variable or auxiliary variable */
13300  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
13301 
13302  return SCIP_OKAY;
13303 }
13304 
13305 /** mark constraints that include this expression to be propagated again
13306  *
13307  * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
13308  * a change of variable bounds, e.g., because new information on the expression is available
13309  * that could potentially lead to tighter expression activity values.
13310  *
13311  * Note, that this call marks also constraints for propagation which only share some variable
13312  * with this expression.
13313  */
13315  SCIP* scip, /**< SCIP data structure */
13316  SCIP_EXPR* expr /**< expression to propagate again */
13317  )
13318 {
13319  SCIP_EXPRITER* it;
13320  SCIP_CONSDATA* consdata;
13321  SCIP_EXPR_OWNERDATA* ownerdata;
13322  int c;
13323 
13324  assert(scip != NULL);
13325  assert(expr != NULL);
13326 
13327  ownerdata = SCIPexprGetOwnerData(expr);
13328  assert(ownerdata != NULL);
13329 
13330  SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
13331 
13332  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13334 
13335  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13336  {
13337  if( !SCIPisExprVar(scip, expr) )
13338  continue;
13339 
13340  ownerdata = SCIPexprGetOwnerData(expr);
13341  assert(ownerdata != NULL);
13342 
13343  for( c = 0; c < ownerdata->nconss; ++c )
13344  {
13345  consdata = SCIPconsGetData(ownerdata->conss[c]);
13346  assert(consdata != NULL);
13347  consdata->ispropagated = FALSE;
13348  }
13349  }
13350 
13351  SCIPfreeExpriter(&it);
13352 
13353  return SCIP_OKAY;
13354 }
13355 
13356 /** adds violation-branching score to an expression
13357  *
13358  * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
13359  * The expression must either be a variable expression or have an aux-variable.
13360  * In the latter case, branching on auxiliary variables must have been enabled.
13361  * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
13362  * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
13363  * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
13364  *
13365  * @see SCIPaddExprsViolScoreNonlinear()
13366  */
13368  SCIP* scip, /**< SCIP data structure */
13369  SCIP_EXPR* expr, /**< expression where to add branching score */
13370  SCIP_Real violscore /**< violation score to add to expression */
13371  )
13372 {
13373  SCIP_EXPR_OWNERDATA* ownerdata;
13374  SCIP_CONSHDLRDATA* conshdlrdata;
13375 
13376  assert(scip != NULL);
13377  assert(expr != NULL);
13378  assert(violscore >= 0.0);
13379 
13380  ownerdata = SCIPexprGetOwnerData(expr);
13381  assert(ownerdata != NULL);
13382 
13383  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13384  assert(conshdlrdata != NULL);
13385 
13386  /* if not allowing to branch on auxvars, then expr must be a var-expr */
13387  assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
13388  /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
13389  assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
13390 
13391  /* reset branching score if we are in a different enfo round */
13392  if( ownerdata->violscoretag != conshdlrdata->enforound )
13393  {
13394  ownerdata->violscoresum = violscore;
13395  ownerdata->violscoremax = violscore;
13396  ownerdata->nviolscores = 1;
13397  ownerdata->violscoretag = conshdlrdata->enforound;
13398  return;
13399  }
13400 
13401  ownerdata->violscoresum += violscore;
13402  if( violscore > ownerdata->violscoremax )
13403  ownerdata->violscoremax = violscore;
13404  ++ownerdata->nviolscores;
13405 }
13406 
13407 /** adds violation-branching score to a set of expressions, distributing the score among all the expressions
13408  *
13409  * Each expression must either be a variable expression or have an aux-variable.
13410  * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
13411  * variables present in `exprs`.
13412  */
13414  SCIP* scip, /**< SCIP data structure */
13415  SCIP_EXPR** exprs, /**< expressions where to add branching score */
13416  int nexprs, /**< number of expressions */
13417  SCIP_Real violscore, /**< violation score to add to expression */
13418  SCIP_SOL* sol, /**< current solution */
13419  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
13420  )
13421 {
13422  SCIP_EXPRITER* it;
13423  SCIP_EXPR** varexprs;
13424  SCIP_EXPR* e;
13425  int nvars;
13426  int varssize;
13427  int i;
13428 
13429  assert(exprs != NULL || nexprs == 0);
13430  assert(success != NULL);
13431 
13432  if( nexprs == 0 )
13433  {
13434  *success = FALSE;
13435  return SCIP_OKAY;
13436  }
13437 
13438  /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
13439  if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
13440  {
13441  addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
13442  return SCIP_OKAY;
13443  }
13444 
13445  /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
13446  nvars = 0;
13447  varssize = 5;
13448  SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
13449 
13450  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13452 
13453  for( i = 0; i < nexprs; ++i )
13454  {
13455  for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
13456  {
13457  assert(e != NULL);
13458 
13459  if( SCIPisExprVar(scip, e) )
13460  {
13461  /* add variable expression to vars array */
13462  if( varssize == nvars )
13463  {
13464  varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
13465  SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
13466  }
13467  assert(varssize > nvars);
13468 
13469  varexprs[nvars++] = e;
13470  }
13471  }
13472  }
13473 
13474  SCIPfreeExpriter(&it);
13475 
13476  addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
13477 
13478  SCIPfreeBufferArray(scip, &varexprs);
13479 
13480  return SCIP_OKAY;
13481 }
13482 
13483 /** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
13485  SCIP_EXPR* expr /**< expression */
13486  )
13487 {
13488  SCIP_EXPR_OWNERDATA* ownerdata;
13489  SCIP_CONSHDLRDATA* conshdlrdata;
13490 
13491  assert(expr != NULL);
13492 
13493  ownerdata = SCIPexprGetOwnerData(expr);
13494  assert(ownerdata != NULL);
13495 
13496  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13497  assert(conshdlrdata != NULL);
13498 
13499  if( conshdlrdata->enforound != ownerdata->violscoretag )
13500  return 0.0;
13501 
13502  if( ownerdata->nviolscores == 0 )
13503  return 0.0;
13504 
13505  switch( conshdlrdata->branchscoreagg )
13506  {
13507  case 'a' :
13508  /* average */
13509  return ownerdata->violscoresum / ownerdata->nviolscores;
13510 
13511  case 'm' :
13512  /* maximum */
13513  return ownerdata->violscoremax;
13514 
13515  case 's' :
13516  /* sum */
13517  return ownerdata->violscoresum;
13518 
13519  default:
13520  SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
13521  SCIPABORT();
13522  return SCIP_INVALID;
13523  }
13524 }
13525 
13526 /** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13527  *
13528  * @see SCIPexprGetDerivative()
13529  */
13531  SCIP* scip, /**< SCIP data structure */
13532  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
13533  SCIP_VAR* var /**< variable (needs to be in the expression) */
13534  )
13535 {
13536  SCIP_EXPR_OWNERDATA* ownerdata;
13537  SCIP_CONSHDLRDATA* conshdlrdata;
13538  SCIP_EXPR* varexpr;
13539 
13540  assert(scip != NULL);
13541  assert(expr != NULL);
13542  assert(var != NULL);
13543 
13544  /* return 0.0 for value expression */
13545  if( SCIPisExprValue(scip, expr) )
13546  {
13547  assert(SCIPexprGetDerivative(expr) == 0.0);
13548  return 0.0;
13549  }
13550 
13551  /* check if an error occurred during the last SCIPevalExprGradient() call */
13552  if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
13553  return SCIP_INVALID;
13554 
13555  ownerdata = SCIPexprGetOwnerData(expr);
13556  assert(ownerdata != NULL);
13557 
13558  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13559  assert(conshdlrdata != NULL);
13560 
13561  /* use variable to expressions mapping which is stored in the constraint handler data */
13562  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13563 
13564  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13565  assert(varexpr != NULL);
13566  assert(SCIPisExprVar(scip, varexpr));
13567 
13568  /* use difftag to decide whether the variable belongs to the expression */
13569  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
13570 }
13571 
13572 /** 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)
13573  *
13574  * @see SCIPexprGetBardot()
13575  */
13577  SCIP* scip, /**< SCIP data structure */
13578  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
13579  SCIP_VAR* var /**< variable (needs to be in the expression) */
13580  )
13581 {
13582  SCIP_EXPR_OWNERDATA* ownerdata;
13583  SCIP_CONSHDLRDATA* conshdlrdata;
13584  SCIP_EXPR* varexpr;
13585 
13586  assert(scip != NULL);
13587  assert(expr != NULL);
13588  assert(var != NULL);
13589 
13590  /* return 0.0 for value expression */
13591  if( SCIPisExprValue(scip, expr) )
13592  return 0.0;
13593 
13594  /* check if an error occurred during the last SCIPevalExprHessianDir() call */
13595  if( SCIPexprGetBardot(expr) == SCIP_INVALID )
13596  return SCIP_INVALID;
13597 
13598  ownerdata = SCIPexprGetOwnerData(expr);
13599  assert(ownerdata != NULL);
13600 
13601  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13602  assert(conshdlrdata != NULL);
13603 
13604  /* use variable to expressions mapping which is stored in the constraint handler data;
13605  * if this fails it means that we are asking for the var's component of H*u for a var
13606  * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
13607  */
13608  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13609 
13610  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13611  assert(varexpr != NULL);
13612  assert(SCIPisExprVar(scip, varexpr));
13613 
13614  /* use difftag to decide whether the variable belongs to the expression */
13615  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
13616 }
13617 
13618 /** evaluates quadratic term in a solution w.r.t. auxiliary variables
13619  *
13620  * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
13621  */
13623  SCIP* scip, /**< SCIP data structure */
13624  SCIP_EXPR* expr, /**< quadratic expression */
13625  SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
13626  )
13627 {
13628  SCIP_Real auxvalue;
13629  int nlinexprs;
13630  SCIP_Real* lincoefs;
13631  SCIP_EXPR** linexprs;
13632  int nquadexprs;
13633  int nbilinexprs;
13634  int i;
13635 
13636  assert(scip != NULL);
13637  assert(expr != NULL);
13638 
13639  SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
13640 
13641  /* linear terms */
13642  for( i = 0; i < nlinexprs; ++i )
13643  {
13644  assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
13645  auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
13646  }
13647 
13648  /* quadratic terms */
13649  for( i = 0; i < nquadexprs; ++i )
13650  {
13651  SCIP_EXPR* quadexprterm;
13652  SCIP_Real lincoef;
13653  SCIP_Real sqrcoef;
13654  SCIP_Real solval;
13655 
13656  SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
13657 
13658  assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
13659 
13660  solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
13661  auxvalue += (lincoef + sqrcoef * solval) * solval;
13662  }
13663 
13664  /* bilinear terms */
13665  for( i = 0; i < nbilinexprs; ++i )
13666  {
13667  SCIP_EXPR* expr1;
13668  SCIP_EXPR* expr2;
13669  SCIP_Real coef;
13670 
13671  SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
13672 
13673  assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
13674  assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
13675  auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
13676  }
13677 
13678  return auxvalue;
13679 }
13680 
13681 /**@addtogroup PublicNlhdlrInterfaceMethods
13682  * @{
13683  */
13684 
13685 /** creates a nonlinear handler and includes it into the nonlinear constraint handler */
13687  SCIP* scip, /**< SCIP data structure */
13688  SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
13689  const char* name, /**< name of nonlinear handler (must not be NULL) */
13690  const char* desc, /**< description of nonlinear handler (can be NULL) */
13691  int detectpriority, /**< detection priority of nonlinear handler */
13692  int enfopriority, /**< enforcement priority of nonlinear handler */
13693  SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
13694  SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
13695  SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
13696  )
13697 {
13698  SCIP_CONSHDLR* conshdlr;
13699  SCIP_CONSHDLRDATA* conshdlrdata;
13700 
13701  assert(scip != NULL);
13702  assert(nlhdlr != NULL);
13703  assert(detect != NULL);
13704 
13705  /* find myself */
13706  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13707  if( conshdlr == NULL )
13708  {
13709  SCIPerrorMessage("nonlinear constraint handler not found");
13710  return SCIP_PLUGINNOTFOUND;
13711  }
13712 
13713  /* create nlhdlr */
13714  SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
13715 
13716  /* include into constraint handler */
13717  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13718  assert(conshdlrdata != NULL);
13719 
13720  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
13721 
13722  conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
13723  ++conshdlrdata->nnlhdlrs;
13724 
13725  /* sort nonlinear handlers by detection priority, in decreasing order
13726  * will happen in INIT, so only do when called late
13727  */
13728  if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
13729  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
13730 
13731  return SCIP_OKAY;
13732 }
13733 
13734 /** get number of nonlinear handler */
13736  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13737  )
13738 {
13739  SCIP_CONSHDLRDATA* conshdlrdata;
13740 
13741  assert(conshdlr != NULL);
13742 
13743  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13744  assert(conshdlrdata != NULL);
13745 
13746  return conshdlrdata->nnlhdlrs;
13747 }
13748 
13749 /** get nonlinear handlers */
13751  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13752  )
13753 {
13754  SCIP_CONSHDLRDATA* conshdlrdata;
13755 
13756  assert(conshdlr != NULL);
13757 
13758  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13759  assert(conshdlrdata != NULL);
13760 
13761  return conshdlrdata->nlhdlrs;
13762 }
13763 
13764 /** returns a nonlinear handler of a given name (or NULL if not found) */
13766  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13767  const char* name /**< name of nonlinear handler */
13768  )
13769 {
13770  SCIP_CONSHDLRDATA* conshdlrdata;
13771  int h;
13772 
13773  assert(conshdlr != NULL);
13774  assert(name != NULL);
13775 
13776  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13777  assert(conshdlrdata != NULL);
13778 
13779  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
13780  if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
13781  return conshdlrdata->nlhdlrs[h];
13782 
13783  return NULL;
13784 }
13785 
13786 /** gives expression data that a given nonlinear handler stored in an expression
13787  *
13788  * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
13789  */
13791  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
13792  SCIP_EXPR* expr /**< expression */
13793  )
13794 {
13795  SCIP_EXPR_OWNERDATA* ownerdata;
13796  int e;
13797 
13798  assert(nlhdlr != NULL);
13799  assert(expr != NULL);
13800 
13801  ownerdata = SCIPexprGetOwnerData(expr);
13802  assert(ownerdata != NULL);
13803 
13804  for( e = 0; e < ownerdata->nenfos; ++e )
13805  if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
13806  return ownerdata->enfos[e]->nlhdlrexprdata;
13807 
13808  return NULL;
13809 }
13810 
13811 /** @} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static SCIP_DECL_CONSENABLE(consEnableNonlinear)
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
static SCIP_RETCODE bilinTermAddAuxExpr(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSNONLINEAR_BILINTERM *term, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_Bool *added)
void SCIProwprepRecordModifications(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:759
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:101
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4205
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2081
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss)
void SCIPexprGetQuadraticData(SCIP_EXPR *expr, SCIP_Real *constant, int *nlinexprs, SCIP_EXPR ***linexprs, SCIP_Real **lincoefs, int *nquadexprs, int *nbilinexprs, SCIP_Real **eigenvalues, SCIP_Real **eigenvectors)
Definition: expr.c:4057
SCIP_Longint SCIPgetExprNewSoltag(SCIP *scip)
Definition: scip_expr.c:1640
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:90
static SCIP_RETCODE enforceExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_RESULT *result)
SCIP_RETCODE SCIPlpiGetNRows(SCIP_LPI *lpi, int *nrows)
Definition: lpi_clp.cpp:1408
SCIP_RETCODE SCIPgetCharParam(SCIP *scip, const char *name, char *value)
Definition: scip_param.c:317
static volatile int nterms
Definition: interrupt.c:38
SCIP_Bool SCIPnlhdlrIsEnabled(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:181
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
Definition: expriter.c:491
static SCIP_RETCODE freeEnfoData(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool freeauxvar)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
Definition: lpi_clp.cpp:634
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8182
SCIP_EXPR_OWNERDATA * SCIPexprGetOwnerData(SCIP_EXPR *expr)
Definition: expr.c:3859
void SCIPexprSetIntegrality(SCIP_EXPR *expr, SCIP_Bool isintegral)
Definition: expr.c:4027
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
primal heuristic that tries a given solution
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:101
static SCIP_Real getExprAbsOrigViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
SCIP_RETCODE SCIPcreateExprPow(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_pow.c:3166
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5200
SCIP_RETCODE SCIPsimplifyExpr(SCIP *scip, SCIP_EXPR *rootexpr, SCIP_EXPR **simplified, SCIP_Bool *changed, SCIP_Bool *infeasible, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1762
SCIP_RETCODE SCIPcreateConsBasicSignpowerNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *x, SCIP_VAR *z, SCIP_Real exponent, SCIP_Real xoffset, SCIP_Real zcoef, SCIP_Real lhs, SCIP_Real rhs)
SCIP_MONOTONE
Definition: type_expr.h:57
void SCIPaddExprViolScoreNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real violscore)
SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
Definition: scip_table.c:47
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3289
SCIP_RETCODE SCIPinsertBilinearTermExistingNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *auxvar, int nlockspos, int nlocksneg)
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:82
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:356
static SCIP_RETCODE addTightEstimatorCut(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *expr, EXPRENFO *exprenfo, SCIP_SOL *sol, SCIP_Bool overestimate, SCIP_PTRARRAY *rowpreps)
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:63
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8344
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip_sol.c:1309
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition: scip_expr.c:1476
SCIP_RETCODE SCIPincludeConsUpgradeNonlinear(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
static SCIP_Bool isBinaryProduct(SCIP *scip, SCIP_EXPR *expr)
SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
Constraint handler for variable bound constraints .
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPdialogMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:182
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
unsigned int SCIPgetExprNAuxvarUsesNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1706
void SCIPsetLPFeastol(SCIP *scip, SCIP_Real newfeastol)
Definition: scip_lp.c:429
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2487
SCIP_RETCODE SCIPaddDialogEntry(SCIP *scip, SCIP_DIALOG *dialog, SCIP_DIALOG *subdialog)
Definition: scip_dialog.c:162
static SCIP_DECL_CONSEXIT(consExitNonlinear)
SCIP_RETCODE SCIPchgExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:345
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
#define SCIP_NLHDLR_METHOD_SEPABELOW
Definition: type_nlhdlr.h:42
static SCIP_RETCODE addLocks(SCIP *scip, SCIP_CONS *cons, int nlockspos, int nlocksneg)
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3798
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:117
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
Definition: lpi_clp.cpp:2774
SCIP_Bool SCIPisUbBetter(SCIP *scip, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
static SCIP_RETCODE addTightEstimatorCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol)
static SCIP_DECL_CONSDISABLE(consDisableNonlinear)
#define SCIP_NLHDLR_METHOD_NONE
Definition: type_nlhdlr.h:41
static SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17910
SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
Definition: lpi_clp.cpp:3678
#define SCIP_MAXSTRLEN
Definition: def.h:293
SCIP_RETCODE SCIPcreateExprSignpower(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_pow.c:3190
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3347
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip_var.c:8811
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:146
int SCIPnlhdlrGetDetectPriority(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:161
const char * SCIPexprhdlrGetName(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:525
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1796
#define SCIP_DECL_CONSGETDIVEBDCHGS(x)
Definition: type_cons.h:909
SCIP_RETCODE SCIPcleanupRowprep2(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefbound, SCIP_Bool *success)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2842
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
#define TABLE_POSITION_NLHDLR
static SCIP_RETCODE freeAuxVar(SCIP *scip, SCIP_EXPR *expr)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17966
SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1172
SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:920
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18273
static SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
static SCIP_RETCODE bilinearTermsInsertEntry(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, int nlockspos, int nlocksneg, int *idx, SCIP_Bool existing)
SCIP_RETCODE SCIPgetRelViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *viol)
SCIP_RETCODE SCIPqueueInsert(SCIP_QUEUE *queue, void *elem)
Definition: misc.c:1020
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:95
SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
Definition: lpi_clp.cpp:1158
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17317
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
Definition: misc_rowprep.c:769
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1436
#define TABLE_EARLIEST_STAGE_NLHDLR
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1245
SCIP_Real SCIPgetBranchingPoint(SCIP *scip, SCIP_VAR *var, SCIP_Real suggestion)
Definition: scip_branch.c:888
SCIP_TABLE * SCIPfindTable(SCIP *scip, const char *name)
Definition: scip_table.c:85
SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:169
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPregisterExprUsageNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool useauxvar, SCIP_Bool useactivityforprop, SCIP_Bool useactivityforsepabelow, SCIP_Bool useactivityforsepaabove)
SCIP_RETCODE SCIPreplaceCommonSubexpressions(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Bool *replacedroot)
Definition: scip_expr.c:1793
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: scip_var.c:8947
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE registerBranchingCandidatesAllUnfixed(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
SCIP_Bool SCIPcliqueHasVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
Definition: implics.c:1132
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10291
static SCIP_RETCODE addExprViolScoresAuxVars(SCIP *scip, SCIP_EXPR *expr, SCIP_Real violscore, SCIP_VAR **auxvars, int nauxvars, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_Bool SCIPassumeConvexNonlinear(SCIP_CONSHDLR *conshdlr)
static SCIP_RETCODE freeVarExprs(SCIP *scip, SCIP_CONSDATA *consdata)
#define SCIP_DECL_CONSRESPROP(x)
Definition: type_cons.h:601
SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
Definition: scip_expr.c:2340
static SCIP_RETCODE computeVertexPolyhedralFacetBivariate(SCIP *scip, SCIP_Bool overestimate, SCIP_Real p1[2], SCIP_Real p2[2], SCIP_Real p3[2], SCIP_Real p4[2], SCIP_Real p1val, SCIP_Real p2val, SCIP_Real p3val, SCIP_Real p4val, SCIP_Real xstar[2], SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
static void findUnlockedLinearVar(SCIP *scip, SCIP_CONS *cons)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4547
#define FALSE
Definition: def.h:87
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:4642
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3014
SCIP_RETCODE SCIPmarkExprPropagateNonlinear(SCIP *scip, SCIP_EXPR *expr)
static SCIP_RETCODE forbidNonlinearVariablesMultiaggration(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
#define TABLE_DESC_NONLINEAR
static SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
static void scoreBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_SOL *sol)
SCIP_RETCODE SCIPduplicateExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **copyexpr, SCIP_DECL_EXPR_MAPEXPR((*mapexpr)), void *mapexprdata, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1271
int SCIPgetNBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:664
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_NLHDLREXPRDATA * SCIPgetNlhdlrExprDataNonlinear(SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10755
void SCIPintervalIntersectEps(SCIP_INTERVAL *resultant, SCIP_Real eps, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_Real getConsAbsViolation(SCIP_CONS *cons)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPchgRhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
Definition: expr_pow.c:3343
#define TRUE
Definition: def.h:86
SCIP_RETCODE SCIPgetNlRowNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static SCIP_RETCODE forwardPropExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *rootexpr, SCIP_Bool tightenauxvars, SCIP_Bool *infeasible, int *ntightenings)
static SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip_var.c:4314
static SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3132
SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI *lpi, SCIP_LPPARAM type, SCIP_Real dval)
Definition: lpi_clp.cpp:3819
#define SCIP_DECL_NLHDLRDETECT(x)
Definition: type_nlhdlr.h:168
int SCIPgetBilinTermIdxNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y)
static SCIP_RETCODE detectNlhdlrs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
int nlockspos[NLOCKTYPES]
Definition: struct_cons.h:54
void SCIPexpriterSetChildUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition: expriter.c:828
SCIP_Real SCIPgetLPFeastol(SCIP *scip)
Definition: scip_lp.c:419
static SCIP_RETCODE initSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:185
int SCIPdialogFindEntry(SCIP_DIALOG *dialog, const char *entryname, SCIP_DIALOG **subdialog)
Definition: dialog.c:1019
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
Definition: lpi_clp.cpp:1426
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition: expr.c:3954
static SCIP_RETCODE scaleConsSides(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *changed)
static GRAPHNODE ** active
void SCIPincrementCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_Bool boundrelax)
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:10278
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5317
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:99
#define CONSHDLR_SEPAFREQ
SCIP_SIDETYPE SCIProwprepGetSidetype(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:644
static SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
void SCIPnlhdlrPrintStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, FILE *file)
Definition: nlhdlr.c:688
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition: misc.c:10003
static SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
int SCIPgetPtrarrayMaxIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
#define TABLE_NAME_NONLINEAR
void SCIPsortDownIntPtr(int *intarray, void **ptrarray, int len)
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip_event.c:225
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:79
Constraint handler for AND constraints, .
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:123
SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:118
static SCIP_RETCODE getBilinearBinaryTerms(SCIP *scip, SCIP_EXPR *sumexpr, SCIP_VAR **xs, SCIP_VAR **ys, int *childidxs, int *nterms)
static SCIP_Bool isConsViolated(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE bilinearTermsInsertAll(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE enforceExprNlhdlr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_SOL *sol, SCIP_Real auxvalue, SCIP_Bool overestimate, SCIP_Bool separated, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_RESULT *result)
#define EPSFRAC(x, eps)
Definition: def.h:213
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3201
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_CONSACTIVE(consActiveNonlinear)
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:361
SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_var.c:381
static SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
SCIP_Bool SCIPqueueIsEmpty(SCIP_QUEUE *queue)
Definition: misc.c:1175
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:4610
SCIP_EXPRITER_USERDATA SCIPexpriterGetCurrentUserData(SCIP_EXPRITER *iterator)
Definition: expriter.c:746
#define SCIP_NLHDLR_METHOD_ALL
Definition: type_nlhdlr.h:46
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition: scip_expr.c:1399
void SCIPsortDown(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5979
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:93
static SCIP_RETCODE createExprVar(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR **expr, SCIP_VAR *var)
void SCIPfreeExprQuadratic(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:2358
variable expression handler
SCIP_RETCODE SCIPcreateConsBasicVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs)
#define CONSHDLR_NAME
SCIP_RETCODE SCIPappendExprSumExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *child, SCIP_Real childcoef)
Definition: expr_sum.c:1107
#define SCIP_EXPRITER_ENTEREXPR
Definition: type_expr.h:667
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8354
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:116
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition: expr.c:4185
static SCIP_RETCODE presolveImplint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nchgvartypes, SCIP_Bool *infeasible)
#define SCIPnlhdlrResetNDetectionslast(nlhdlr)
Definition: nlhdlr.h:117
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17278
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:111
#define SCIPdebugMsgPrint
Definition: scip_message.h:70
#define SCIPdebugMsg
Definition: scip_message.h:69
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:74
SCIP_RETCODE SCIPcreateExprSum(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefficients, SCIP_Real constant, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_sum.c:1070
SCIP_RETCODE SCIPaddLinearCoefToNlRow(SCIP *scip, SCIP_NLROW *nlrow, SCIP_VAR *var, SCIP_Real val)
Definition: scip_nlp.c:1107
SCIP_EXPRCURV SCIPgetCurvatureNonlinear(SCIP_CONS *cons)
SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
Definition: expriter.c:673
SCIP_VAR ** x
Definition: circlepacking.c:54
SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
Definition: lpi_clp.cpp:522
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8146
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18262
SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1656
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2171
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:934
struct SCIP_Expr_OwnerData SCIP_EXPR_OWNERDATA
Definition: type_expr.h:68
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1454
static SCIP_RETCODE collectBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, BRANCHCAND *cands, int *ncands)
SCIP_HASHMAP * SCIPgetVarExprHashmapNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2236
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8384
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1623
#define ENFOLOG(x)
#define consInitpreNonlinear
SCIP_RETCODE SCIPcreateConsBasicSOCNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *coefs, SCIP_Real *offsets, SCIP_Real constant, SCIP_VAR *rhsvar, SCIP_Real rhscoeff, SCIP_Real rhsoffset)
static SCIP_RETCODE getConsRelViolation(SCIP *scip, SCIP_CONS *cons, SCIP_Real *viol, SCIP_SOL *sol, SCIP_Longint soltag)
SCIP_RETCODE SCIPclearPtrarray(SCIP *scip, SCIP_PTRARRAY *ptrarray)
SCIP_RETCODE SCIPgetAbsViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *viol)
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3363
SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:624
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
Definition: scip_branch.c:840
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:243
SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7434
void * SCIPgetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx)
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1871
static SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:8173
static SCIP_RETCODE createAuxVar(SCIP *scip, SCIP_EXPR *expr)
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3808
SCIP_DIALOG * SCIPgetRootDialog(SCIP *scip)
Definition: scip_dialog.c:148
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17920
SCIP_Bool active
SCIP_VAR * w
Definition: circlepacking.c:58
SCIP_RETCODE SCIPincludeDialog(SCIP *scip, SCIP_DIALOG **dialog, SCIP_DECL_DIALOGCOPY((*dialogcopy)), SCIP_DECL_DIALOGEXEC((*dialogexec)), SCIP_DECL_DIALOGDESC((*dialogdesc)), SCIP_DECL_DIALOGFREE((*dialogfree)), const char *name, const char *desc, SCIP_Bool issubmenu, SCIP_DIALOGDATA *dialogdata)
Definition: scip_dialog.c:50
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:108
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:135
SCIP_Real inf
Definition: intervalarith.h:46
static SCIP_RETCODE bilinearTermsFree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
static SCIP_Bool branchAuxNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip_sol.c:609
static SCIP_DECL_CONSCHECK(consCheckNonlinear)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:603
SCIP_NLHDLR ** SCIPgetNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_EXPR * expr
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_EXPRITER *it, SCIP_Bool allowweakcuts, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Bool *success)
static SCIP_Bool isSingleLockedCand(SCIP *scip, SCIP_EXPR *expr)
#define SCIP_DECL_NONLINCONSUPGD(x)
SCIP_Real SCIPgetExprViolScoreNonlinear(SCIP_EXPR *expr)
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_Real pscost
static SCIP_RETCODE createCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool copyexpr, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1853
SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1157
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1441
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition: expr.c:3970
SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:67
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:604
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:249
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition: expr.c:3872
SCIP_RETCODE SCIPcreateConsBasicQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs)
#define TABLE_DESC_NLHDLR
#define SCIPerrorMessage
Definition: pub_message.h:55
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4175
#define CONSHDLR_ENFOPRIORITY
static SCIP_DECL_CONSINITLP(consInitlpNonlinear)
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2769
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition: expr.c:3898
SCIP_Bool SCIProwprepIsLocal(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:654
#define TABLE_POSITION_NONLINEAR
static void addExprsViolScore(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_RETCODE SCIPcomputeFacetVertexPolyhedralNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_DECL_VERTEXPOLYFUN((*function)), void *fundata, SCIP_Real *xstar, SCIP_Real *box, int nallvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
static SCIP_RETCODE propExprDomains(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds)
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:354
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:17117
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPnlhdlrCreate(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
Definition: nlhdlr.c:306
int SCIPgetExprNEnfosNonlinear(SCIP_EXPR *expr)
const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:141
#define SCIP_DECL_NLHDLREVALAUX(x)
Definition: type_nlhdlr.h:193
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3473
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
static SCIP_RETCODE analyzeViolation(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Real *maxabsconsviol, SCIP_Real *maxrelconsviol, SCIP_Real *minauxviol, SCIP_Real *maxauxviol, SCIP_Real *maxvarboundviol)
#define CONSHDLR_PROP_TIMING
SCIP_Bool SCIPexprhdlrHasMonotonicity(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:645
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition: expr_var.c:407
static SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
SCIP_Bool SCIPnlhdlrHasIntEval(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:201
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1016
SCIP_RETCODE SCIPgetExprAbsOrigViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
SCIP_RETCODE SCIPcollectBilinTermsNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE dropVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeNlhdlrNonlinear(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:128
SCIP_RETCODE SCIPcreateConsBasicNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs)
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:474
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:48
static SCIP_RETCODE removeSingleLockedVars(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRITER *it, SCIP_HASHMAP *exprcands)
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
static SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
SCIP_RETCODE SCIPcreateConsQuadraticNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8085
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8712
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1432
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8304
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:164
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17251
static SCIP_Real getViolSplitWeight(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var, SCIP_SOL *sol)
SCIP_RETCODE SCIPcreateConsBasicAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars)
Definition: cons_and.c:5129
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3048
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4195
SCIP_EXPR * SCIPgetExprNonlinear(SCIP_CONS *cons)
void SCIPexprGetQuadraticQuadTerm(SCIP_EXPR *quadexpr, int termidx, SCIP_EXPR **expr, SCIP_Real *lincoef, SCIP_Real *sqrcoef, int *nadjbilin, int **adjbilin, SCIP_EXPR **sqrexpr)
Definition: expr.c:4104
#define NULL
Definition: lpi_spx1.cpp:155
static SCIP_RETCODE computeHyperplaneThreePoints(SCIP *scip, SCIP_Real a1, SCIP_Real a2, SCIP_Real a3, SCIP_Real b1, SCIP_Real b2, SCIP_Real b3, SCIP_Real c1, SCIP_Real c2, SCIP_Real c3, SCIP_Real *alpha, SCIP_Real *beta, SCIP_Real *gamma_, SCIP_Real *delta)
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2604
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1482
unsigned int SCIPgetExprNPropUsesActivityNonlinear(SCIP_EXPR *expr)
SCIP_Real auxvalue
SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermNonlinear(SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y)
static SCIP_RETCODE getBinaryProductExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_HASHMAP *exprmap, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, int *nchgcoefs)
power and signed power expression handlers
#define REALABS(x)
Definition: def.h:201
SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
Definition: scip_expr.c:2069
SCIP_RETCODE SCIPaddExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_Real coef)
SCIP_Real SCIPexprGetBardot(SCIP_EXPR *expr)
Definition: expr.c:3926
static SCIP_RETCODE deinitSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPreplaceExprChild(SCIP *scip, SCIP_EXPR *expr, int childidx, SCIP_EXPR *newchild)
Definition: scip_expr.c:1238
SCIP_Longint SCIPexprGetDiffTag(SCIP_EXPR *expr)
Definition: expr.c:3941
#define DIALOG_NAME
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1443
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
Definition: misc_rowprep.c:558
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition: scip_sepa.c:330
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_DECL_CONSDELVARS(ConshdlrSubtour::scip_delvars)
SCIP_RETCODE SCIPsolveLinearEquationsIpopt(int N, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x, SCIP_Bool *success)
#define SCIP_CALL(x)
Definition: def.h:384
#define SCIPhashTwo(a, b)
Definition: pub_misc.h:510
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:697
SCIP_Real SCIPgetExprPartialDiffGradientDirNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_VAR *var)
#define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
Definition: scip_mem.h:98
int SCIPgetNTotalVars(SCIP *scip)
Definition: scip_prob.c:2568
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1117
SCIP_VAR * h
Definition: circlepacking.c:59
SCIP_Real sup
Definition: intervalarith.h:47
SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_value.c:261
SCIP_Longint SCIPexprGetEvalTag(SCIP_EXPR *expr)
Definition: expr.c:3885
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define consGetDiveBdChgsNonlinear
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8324
Definition: graph_load.c:93
SCIP_RETCODE SCIPhasExprCurvature(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRCURV curv, SCIP_Bool *success, SCIP_HASHMAP *assumevarfixed)
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Bool *reliable)
Definition: misc_rowprep.c:940
SCIP_VAR ** SCIProwprepGetModifiedVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:684
void SCIPgetExprEnfoDataNonlinear(SCIP_EXPR *expr, int idx, SCIP_NLHDLR **nlhdlr, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_NLHDLR_METHOD *nlhdlrparticipation, SCIP_Bool *sepabelowusesactivity, SCIP_Bool *sepaaboveusesactivity, SCIP_Real *auxvalue)
void SCIPqueueFree(SCIP_QUEUE **queue)
Definition: misc.c:958
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:241
const char * SCIPnlhdlrGetDesc(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:151
#define VERTEXPOLY_USEDUALSIMPLEX
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:56
static SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
static SCIP_Bool isIntervalBetter(SCIP *scip, SCIP_Bool subsetsufficient, SCIP_INTERVAL newinterval, SCIP_INTERVAL oldinterval)
#define SCIP_INTERVAL_INFINITY
Definition: def.h:199
static SCIP_RETCODE computeVertexPolyhedralFacetLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_Real *xstar, SCIP_Real *box, int nallvars, int *nonfixedpos, SCIP_Real *funvals, int nvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
#define SCIPallocClearMemory(scip, ptr)
Definition: scip_mem.h:53
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:114
#define VERTEXPOLY_RANDNUMINITSEED
union SCIP_ConsNonlinear_BilinTerm::@4 aux
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4590
SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2300
#define TABLE_NAME_NLHDLR
SCIP_Real SCIPgetCoefExprProduct(SCIP_EXPR *expr)
nonlinear handlers for convex and concave expressions, respectively
SCIP_RETCODE SCIPaddLinearVarNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
int SCIPgetExprNLocksNegNonlinear(SCIP_EXPR *expr)
int SCIProwprepGetNModifiedVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:674
Ipopt NLP interface.
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1212
#define CONSHDLR_CHECKPRIORITY
SCIP_RETCODE SCIPcheckQuadraticNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *isquadratic)
SCIP_Real SCIPgetExprPartialDiffNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_VAR *var)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Longint soltag)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1044
#define SCIP_Bool
Definition: def.h:84
#define infty2infty(infty1, infty2, val)
static SCIP_RETCODE canonicalizeConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_PRESOLTIMING presoltiming, SCIP_Bool *infeasible, int *ndelconss, int *naddconss, int *nchgcoefs)
SCIP_EXPR * SCIPexpriterRestartDFS(SCIP_EXPRITER *iterator, SCIP_EXPR *expr)
Definition: expriter.c:620
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:277
static SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:159
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPexprhdlrHasReverseProp(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:655
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1021
SCIP_RETCODE SCIPchgNlRowConstant(SCIP *scip, SCIP_NLROW *nlrow, SCIP_Real constant)
Definition: scip_nlp.c:1084
SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:3905
static const char * paramname[]
Definition: lpi_msk.c:5031
SCIP_RETCODE SCIPnlhdlrFree(SCIP *scip, SCIP_NLHDLR **nlhdlr)
Definition: nlhdlr.c:353
SCIP_EXPRCURV
Definition: type_expr.h:48
SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2595
SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
Definition: cons.c:8203
SCIP_RETCODE SCIPcopyExpr(SCIP *sourcescip, SCIP *targetscip, SCIP_EXPR *expr, SCIP_EXPR **copyexpr, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *valid)
Definition: scip_expr.c:1308
SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:310
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition: var.c:17556
SCIP_Bool SCIPdialogHasEntry(SCIP_DIALOG *dialog, const char *entryname)
Definition: dialog.c:986
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:661
unsigned int SCIP_NLHDLR_METHOD
Definition: type_nlhdlr.h:48
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1407
constraint handler for nonlinear constraints specified by algebraic expressions
static SCIP_RETCODE tightenAuxVarBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *expr, SCIP_INTERVAL bounds, SCIP_Bool *cutoff, int *ntightenings)
static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
static SCIP_RETCODE presolveSingleLockedVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *nchgvartypes, int *naddconss, SCIP_Bool *infeasible)
#define MAX(x, y)
Definition: tclique_def.h:83
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10856
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:352
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8105
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11941
static SCIP_RETCODE presolveBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddconss, int *nchgcoefs)
methods for debugging
#define SCIPnlhdlrIncrementNCutoffs(nlhdlr)
Definition: nlhdlr.h:118
#define CONSHDLR_PROPFREQ
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8214
static SCIP_RETCODE detectNlhdlr(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons)
SCIP_RETCODE SCIPparseExpr(SCIP *scip, SCIP_EXPR **expr, const char *exprstr, const char **finalpos, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1370
#define CONSHDLR_NEEDSCONS
SCIP_RETCODE SCIPgetExprNVars(SCIP *scip, SCIP_EXPR *expr, int *nvars)
Definition: scip_expr.c:2031
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:85
SCIP_RETCODE SCIPchgLhsNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:311
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:976
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8284
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8254
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17758
SCIP_Longint SCIPgetLastBoundRelaxTagNonlinear(SCIP_CONSHDLR *conshdlr)
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:391
static SCIP_RETCODE catchVarEvent(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_EXPR *expr, SCIP_CONS *cons)
static SCIP_RETCODE getFactorizedBinaryQuadraticExpr(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_EXPR *sumexpr, int minterms, SCIP_EXPR **newexpr, int *naddconss)
#define CONSHDLR_DELAYSEPA
SCIP_Bool SCIPexprIsIntegral(SCIP_EXPR *expr)
Definition: expr.c:4017
SCIP_RETCODE SCIPcomputeExprIntegrality(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1988
SCIP_Real SCIPevalBilinAuxExprNonlinear(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, SCIP_CONSNONLINEAR_AUXEXPR *auxexpr, SCIP_SOL *sol)
SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
Definition: expriter.c:848
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:656
SCIP_NLHDLREXPRDATA * nlhdlrexprdata
#define BILIN_MAXNAUXEXPRS
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip_nlp.c:912
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:49
SCIP_EXPR * SCIPexpriterGetChildExprDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:711
#define consDelvarsNonlinear
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:17621
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition: expr.c:3821
Constraint handler for linear constraints in their most general form, .
static SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2219
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2548
SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1465
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip_cut.c:198
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSPROP(consPropNonlinear)
SCIP_Real dual
static SCIP_RETCODE replaceBinaryProducts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_HASHMAP *exprmap, SCIP_EXPRITER *it, int *naddconss, int *nchgcoefs)
static SCIP_DECL_EVENTEXEC(processVarEvent)
SCIP_RETCODE SCIPdialoghdlrAddHistory(SCIP_DIALOGHDLR *dialoghdlr, SCIP_DIALOG *dialog, const char *command, SCIP_Bool escapecommand)
Definition: dialog.c:717
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2036
SCIP_RETCODE SCIPtightenExprIntervalNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_INTERVAL newbounds, SCIP_Bool *cutoff, int *ntightenings)
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10025
int SCIPnlhdlrGetEnfoPriority(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:171
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:88
SCIP_CONSHDLR * SCIProwGetOriginConshdlr(SCIP_ROW *row)
Definition: lp.c:17422
constant value expression handler
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2286
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1991
#define SCIP_REAL_MAX
Definition: def.h:178
#define CONSHDLR_SEPAPRIORITY
SCIP_RETCODE SCIPsetNlRowExpr(SCIP *scip, SCIP_NLROW *nlrow, SCIP_EXPR *expr)
Definition: scip_nlp.c:1194
void SCIPexpriterSetStagesDFS(SCIP_EXPRITER *iterator, SCIP_EXPRITER_STAGE stopstages)
Definition: expriter.c:654
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:382
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2314
static SCIP_DECL_CONSDELETE(consDeleteNonlinear)
void SCIPenableNLP(SCIP *scip)
Definition: scip_nlp.c:86
#define SCIPfreeMemory(scip, ptr)
Definition: scip_mem.h:69
#define BRANCH_RANDNUMINITSEED
SCIP_Real * r
Definition: circlepacking.c:50
static SCIP_RETCODE computeVertexPolyhedralFacetUnivariate(SCIP *scip, SCIP_Real left, SCIP_Real right, SCIP_Real funleft, SCIP_Real funright, SCIP_Bool *success, SCIP_Real *facetcoef, SCIP_Real *facetconstant)
static SCIP_DECL_CONSTRANS(consTransNonlinear)
SCIP_Bool SCIPconsIsSeparationEnabled(SCIP_CONS *cons)
Definition: cons.c:8192
int SCIPgetExprNLocksPosNonlinear(SCIP_EXPR *expr)
#define CONSHDLR_PRESOLTIMING
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1553
#define SCIP_EVENTTYPE_BESTSOLFOUND
Definition: type_event.h:96
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3379
static SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
SCIP_Real vartype
static SCIP_RETCODE reformulateFactorizedBinaryQuadratic(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_VAR *facvar, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_EXPR **newexpr, int *naddconss)
int SCIPconshdlrGetMaxNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4924
#define VERTEXPOLY_MAXPERTURBATION
SCIP_RETCODE SCIPcreatePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
SCIP_DIALOG * SCIPdialoghdlrGetRoot(SCIP_DIALOGHDLR *dialoghdlr)
Definition: dialog.c:427
int SCIPhashmapGetNElements(SCIP_HASHMAP *hashmap)
Definition: misc.c:3473
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:238
static SCIP_RETCODE reversePropQueue(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool *infeasible, int *ntightenings)
static SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
SCIP_RETCODE SCIPprocessRowprepNonlinear(SCIP *scip, SCIP_NLHDLR *nlhdlr, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_ROWPREP *rowprep, SCIP_Bool overestimate, SCIP_VAR *auxvar, SCIP_Real auxvalue, SCIP_Bool allowweakcuts, SCIP_Bool branchscoresuccess, SCIP_Bool inenforcement, SCIP_SOL *sol, SCIP_RESULT *result)
#define POWEROFTWO(x)
SCIP_RETCODE SCIPqueueCreate(SCIP_QUEUE **queue, int initsize, SCIP_Real sizefac)
Definition: misc.c:934
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:158
static SCIP_Real getExprAbsAuxViolation(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Bool *violunder, SCIP_Bool *violover)
#define CONSHDLR_DELAYPROP
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1667
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8115
SCIP_RETCODE SCIPlpiLoadColLP(SCIP_LPI *lpi, SCIP_OBJSEN objsen, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition: lpi_clp.cpp:668
SCIP_Real SCIPgetHugeValue(SCIP *scip)
static SCIP_RETCODE presolveMergeConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
SCIP_Real weighted
SCIP_RETCODE SCIPresetClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:135
SCIP_Real SCIProwprepGetSide(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:634
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:143
static SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1110
#define DIALOG_ISSUBMENU
void SCIPgetLinvarMayDecreaseNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **var, SCIP_Real *coef)
SCIP_Longint SCIPgetCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_EXPRITER_STAGE SCIPexpriterGetStageDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:686
void SCIPexpriterSetCurrentUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition: expriter.c:796
#define SCIP_NLHDLR_METHOD_ACTIVITY
Definition: type_nlhdlr.h:45
SCIP_NLHDLR * nlhdlr
NLP local search primal heuristic using sub-SCIPs.
static SCIP_RETCODE branching(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Real maxrelconsviol, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_RESULT *result)
#define SCIP_MAXVERTEXPOLYDIM
SCIP_VAR * a
Definition: circlepacking.c:57
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1421
#define SCIP_DECL_VERTEXPOLYFUN(f)
SCIP_RETCODE SCIPgetExprAbsAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition: expr.c:4147
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1946
int SCIPgetNNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17370
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
default user interface dialog
SCIP_RETCODE SCIPincludeConshdlrNonlinear(SCIP *scip)
SCIP_RETCODE SCIPaddExprsViolScoreNonlinear(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1211
#define SCIP_Real
Definition: def.h:177
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8334
#define CONSHDLR_EAGERFREQ
static SCIP_DECL_CONSFREE(consFreeNonlinear)
#define EPSROUND(x, eps)
Definition: def.h:212
static SCIP_RETCODE propConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool force, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE storeVarExprs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata)
static SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
SCIP_VAR ** y
Definition: circlepacking.c:55
static SCIP_RETCODE enforceConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool inenforcement, SCIP_Real maxrelconsviol, SCIP_RESULT *result)
#define TABLE_EARLIEST_STAGE_NONLINEAR
void SCIPexprSetActivity(SCIP_EXPR *expr, SCIP_INTERVAL activity, SCIP_Longint activitytag)
Definition: expr.c:3980
SCIP_RETCODE SCIPgetExprRelAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
static SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8274
#define SCIP_INVALID
Definition: def.h:197
static SCIP_Real getDualBranchscore(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8264
SCIP_Bool SCIPnlhdlrHasEstimate(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:241
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2197
SCIP_Bool SCIPnlhdlrHasInitSepa(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:217
SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
Definition: expr_value.c:285
static SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
SCIP_RETCODE SCIPcreateConsNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
#define SCIP_Longint
Definition: def.h:162
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17590
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1181
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
Definition: type_nlhdlr.h:404
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:280
static SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
#define SCIPisFinite(x)
Definition: pub_misc.h:1892
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17416
void * SCIPqueueRemove(SCIP_QUEUE *queue)
Definition: misc.c:1071
#define VERTEXPOLY_ADJUSTFACETFACTOR
SCIP_RETCODE SCIPreleaseDialog(SCIP *scip, SCIP_DIALOG **dialog)
Definition: scip_dialog.c:115
struct SCIP_NlhdlrData SCIP_NLHDLRDATA
Definition: type_nlhdlr.h:403
SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
Definition: lpi_clp.cpp:1231
#define CONSHDLR_MAXPREROUNDS
static SCIP_DECL_CONSPRINT(consPrintNonlinear)
#define SCIP_EXPRITER_LEAVEEXPR
Definition: type_expr.h:670
SCIP_RETCODE SCIPinsertBilinearTermImplicitNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *auxvar, SCIP_Real coefx, SCIP_Real coefy, SCIP_Real coefaux, SCIP_Real cst, SCIP_Bool overestimate)
static SCIP_DECL_CONSINIT(consInitNonlinear)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
sum expression handler
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
enum SCIP_Vartype SCIP_VARTYPE
Definition: type_var.h:60
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:55
static SCIP_RETCODE propagateLocks(SCIP *scip, SCIP_EXPR *expr, int nlockspos, int nlocksneg)
void SCIPsetExprEnfoAuxValueNonlinear(SCIP_EXPR *expr, int idx, SCIP_Real auxvalue)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17976
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
Definition: misc_rowprep.c:881
int SCIPgetPtrarrayMinIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:102
#define DIALOG_DESC
unsigned int SCIPgetExprNSepaUsesActivityNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:1932
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real minviol, SCIP_Real *viol, SCIP_Bool *success)
#define SCIP_EXPRITER_VISITINGCHILD
Definition: type_expr.h:668
SCIP_Real SCIPgetUpperbound(SCIP *scip)
static SCIP_RETCODE getBinaryProductExprDo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *prodexpr, SCIP_EXPR **newexpr, int *naddconss, SCIP_Bool empathy4and)
static SCIP_RETCODE consEnfo(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
SCIP_Real auxviol
SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:3096
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:123
SCIP_RETCODE SCIPincludeConshdlr(SCIP *scip, const char *name, const char *desc, int sepapriority, int enfopriority, int chckpriority, int sepafreq, int propfreq, int eagerfreq, int maxprerounds, SCIP_Bool delaysepa, SCIP_Bool delayprop, SCIP_Bool needscons, SCIP_PROPTIMING proptiming, SCIP_PRESOLTIMING presoltiming, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSFREE((*consfree)), SCIP_DECL_CONSINIT((*consinit)), SCIP_DECL_CONSEXIT((*consexit)), SCIP_DECL_CONSINITPRE((*consinitpre)), SCIP_DECL_CONSEXITPRE((*consexitpre)), SCIP_DECL_CONSINITSOL((*consinitsol)), SCIP_DECL_CONSEXITSOL((*consexitsol)), SCIP_DECL_CONSDELETE((*consdelete)), SCIP_DECL_CONSTRANS((*constrans)), SCIP_DECL_CONSINITLP((*consinitlp)), SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFORELAX((*consenforelax)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSPROP((*consprop)), SCIP_DECL_CONSPRESOL((*conspresol)), SCIP_DECL_CONSRESPROP((*consresprop)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_DECL_CONSACTIVE((*consactive)), SCIP_DECL_CONSDEACTIVE((*consdeactive)), SCIP_DECL_CONSENABLE((*consenable)), SCIP_DECL_CONSDISABLE((*consdisable)), SCIP_DECL_CONSDELVARS((*consdelvars)), SCIP_DECL_CONSPRINT((*consprint)), SCIP_DECL_CONSCOPY((*conscopy)), SCIP_DECL_CONSPARSE((*consparse)), SCIP_DECL_CONSGETVARS((*consgetvars)), SCIP_DECL_CONSGETNVARS((*consgetnvars)), SCIP_DECL_CONSGETDIVEBDCHGS((*consgetdivebdchgs)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:73
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
private functions of nonlinear handlers of nonlinear constraints
#define SCIPallocClearBlockMemory(scip, ptr)
Definition: scip_mem.h:82
#define CONSHDLR_DESC
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition: expriter.c:959
SCIPallocBlockMemory(scip, subsol))
static SCIP_RETCODE consSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3221
static SCIP_RETCODE presolveRedundantConss(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool *cutoff, int *ndelconss, int *nchgbds)
static SCIP_DECL_CONSLOCK(consLockNonlinear)
SCIP_RETCODE SCIPlpiChgObjsen(SCIP_LPI *lpi, SCIP_OBJSEN objsen)
Definition: lpi_clp.cpp:1211
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPevalExprQuadraticAuxNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol)
constraint handler for bound disjunction constraints
#define consRespropNonlinear
static SCIP_DECL_CONSPRESOL(consPresolNonlinear)
#define SCIPABORT()
Definition: def.h:356
static SCIP_DECL_CONSPARSE(consParseNonlinear)
SCIP_INTERVAL SCIPgetExprBoundsNonlinear(SCIP *scip, SCIP_EXPR *expr)
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition: lp.c:17106
static SCIP_Real computeVertexPolyhedralMaxFacetError(SCIP *scip, SCIP_Bool overestimate, SCIP_Real *funvals, SCIP_Real *box, int nallvars, int nvars, int *nonfixedpos, SCIP_Real *facetcoefs, SCIP_Real facetconstant)
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17442
SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
#define SCIP_NLHDLR_METHOD_SEPABOTH
Definition: type_nlhdlr.h:44
SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:152
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352
static SCIP_DECL_SORTINDCOMP(branchcandCompare)
int SCIPexprGetNUses(SCIP_EXPR *expr)
Definition: expr.c:3788
#define SCIP_NLHDLR_METHOD_SEPAABOVE
Definition: type_nlhdlr.h:43
#define SCIPnlhdlrIncrementNSeparated(nlhdlr)
Definition: nlhdlr.h:119
void SCIPnlrowSetCurvature(SCIP_NLROW *nlrow, SCIP_EXPRCURV curvature)
Definition: nlp.c:1833
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1328
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:130
SCIP_Bool SCIPcolIsInLP(SCIP_COL *col)
Definition: lp.c:17081
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_CONSNONLINEAR_AUXEXPR ** exprs
static SCIP_DECL_CONSCOPY(consCopyNonlinear)
SCIP_RETCODE SCIPcreateExprQuadratic(SCIP *scip, SCIP_EXPR **expr, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1023
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:48
void SCIPgetLinvarMayIncreaseNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **var, SCIP_Real *coef)
static SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:614
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:119
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:142
SCIP_RETCODE SCIPfreePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
static SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
SCIP_Real domain
#define SCIP_EVENTTYPE_BOUNDRELAXED
Definition: type_event.h:115
static SCIP_RETCODE buildVertexPolyhedralSeparationLP(SCIP *scip, int nvars, SCIP_LPI **lp)
static SCIP_RETCODE initSolve(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss)