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, 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  */
5636 static
5638  SCIP* scip, /**< SCIP data structure */
5639  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5640  SCIP_CONS* cons, /**< nonlinear constraint */
5641  int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5642  int* naddconss, /**< pointer to store the total number of added constraints */
5643  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5644  )
5645 {
5646  SCIP_CONSHDLRDATA* conshdlrdata;
5647  SCIP_CONSDATA* consdata;
5648  SCIP_EXPR** singlelocked;
5649  SCIP_HASHMAP* exprcands;
5650  SCIP_Bool hasbounddisj;
5651  SCIP_Bool haslhs;
5652  SCIP_Bool hasrhs;
5653  int nsinglelocked = 0;
5654  int i;
5655 
5656  assert(conshdlr != NULL);
5657  assert(cons != NULL);
5658  assert(nchgvartypes != NULL);
5659  assert(naddconss != NULL);
5660  assert(infeasible != NULL);
5661 
5662  *nchgvartypes = 0;
5663  *naddconss = 0;
5664  *infeasible = FALSE;
5665 
5666  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5667  assert(conshdlrdata != NULL);
5668  consdata = SCIPconsGetData(cons);
5669  assert(consdata != NULL);
5670 
5671  /* only consider constraints with one finite side */
5672  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5673  return SCIP_OKAY;
5674 
5675  /* only consider sum expressions */
5676  if( !SCIPisExprSum(scip, consdata->expr) )
5677  return SCIP_OKAY;
5678 
5679  /* remember which side is finite */
5680  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5681  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5682 
5683  /* allocate memory */
5684  SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5685  SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5686 
5687  /* check all variable expressions for single locked variables */
5688  for( i = 0; i < consdata->nvarexprs; ++i )
5689  {
5690  assert(consdata->varexprs[i] != NULL);
5691 
5692  if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5693  {
5694  SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5695  singlelocked[nsinglelocked++] = consdata->varexprs[i];
5696  }
5697  }
5698  SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5699 
5700  if( nsinglelocked > 0 )
5701  {
5702  SCIP_EXPR** children;
5703  SCIP_EXPRITER* it;
5704  int nchildren;
5705 
5706  children = SCIPexprGetChildren(consdata->expr);
5707  nchildren = SCIPexprGetNChildren(consdata->expr);
5708 
5709  /* create iterator */
5710  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
5713 
5714  for( i = 0; i < nchildren; ++i )
5715  {
5716  SCIP_EXPR* child;
5717  SCIP_Real coef;
5718 
5719  child = children[i];
5720  assert(child != NULL);
5721  coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5722 
5723  /* ignore linear terms */
5724  if( SCIPisExprVar(scip, child) )
5725  continue;
5726 
5727  /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5728  * expression that represents f_j and remove each variable expression from exprcands
5729  */
5730  else if( SCIPisExprProduct(scip, child) )
5731  {
5732  int j;
5733 
5734  for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5735  {
5736  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5737 
5738  if( !SCIPisExprVar(scip, grandchild) )
5739  {
5740  /* mark all variable expressions that are contained in the expression */
5741  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5742  }
5743  }
5744  }
5745  /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5746  * for an integer k >= 1
5747  */
5748  else if( SCIPisExprPower(scip, child) )
5749  {
5750  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5751  SCIP_Real exponent = SCIPgetExponentExprPow(child);
5752  SCIP_Bool valid;
5753 
5754  /* check for even integral exponent */
5755  valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5756 
5757  if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5758  {
5759  /* mark all variable expressions that are contained in the expression */
5760  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5761  }
5762  }
5763  /* all other cases cannot be handled */
5764  else
5765  {
5766  /* mark all variable expressions that are contained in the expression */
5767  SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5768  }
5769  }
5770 
5771  /* free expression iterator */
5772  SCIPfreeExpriter(&it);
5773  }
5774 
5775  /* check whether the bound disjunction constraint handler is available */
5776  hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5777 
5778  /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5779  for( i = 0; i < nsinglelocked; ++i )
5780  {
5781  /* only consider expressions that are still contained in the exprcands map */
5782  if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5783  {
5784  SCIP_CONS* newcons;
5785  SCIP_VAR* vars[2];
5786  SCIP_BOUNDTYPE boundtypes[2];
5787  SCIP_Real bounds[2];
5788  char name[SCIP_MAXSTRLEN];
5789  SCIP_VAR* var;
5790 
5791  var = SCIPgetVarExprVar(singlelocked[i]);
5792  assert(var != NULL);
5793  SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5795 
5796  /* try to change the variable type to binary */
5797  if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5798  {
5799  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5800  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5801  ++(*nchgvartypes);
5802 
5803  if( *infeasible )
5804  {
5805  SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5806  break;
5807  }
5808  }
5809  /* add bound disjunction constraint if bounds of the variable are finite */
5810  else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5811  {
5812  vars[0] = var;
5813  vars[1] = var;
5814  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5815  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5816  bounds[0] = SCIPvarGetUbGlobal(var);
5817  bounds[1] = SCIPvarGetLbGlobal(var);
5818 
5819  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5820 
5821  /* create, add, and release bound disjunction constraint */
5822  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5823  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5824  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5825  SCIP_CALL( SCIPaddCons(scip, newcons) );
5826  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5827  ++(*naddconss);
5828  }
5829  }
5830  }
5831 
5832  /* free memory */
5833  SCIPfreeBufferArray(scip, &singlelocked);
5834  SCIPhashmapFree(&exprcands);
5835 
5836  return SCIP_OKAY;
5837 }
5838 
5839 /** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5840 static
5842  SCIP* scip, /**< SCIP data structure */
5843  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5844  SCIP_CONS** conss, /**< nonlinear constraints */
5845  int nconss, /**< total number of nonlinear constraints */
5846  int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5847  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5848  )
5849 {
5850  int c;
5851 
5852  assert(scip != NULL);
5853  assert(conshdlr != NULL);
5854  assert(conss != NULL || nconss == 0);
5855  assert(nchgvartypes != NULL);
5856  assert(infeasible != NULL);
5857 
5858  *infeasible = FALSE;
5859 
5860  /* nothing can be done if there are no binary and integer variables available */
5861  if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5862  return SCIP_OKAY;
5863 
5864  /* no continuous var can be made implicit-integer if there are no continuous variables */
5865  if( SCIPgetNContVars(scip) == 0 )
5866  return SCIP_OKAY;
5867 
5868  for( c = 0; c < nconss; ++c )
5869  {
5870  SCIP_CONSDATA* consdata;
5871  SCIP_EXPR** children;
5872  int nchildren;
5873  SCIP_Real* coefs;
5874  SCIP_EXPR* cand = NULL;
5875  SCIP_Real candcoef = 0.0;
5876  int i;
5877 
5878  assert(conss != NULL && conss[c] != NULL);
5879 
5880  consdata = SCIPconsGetData(conss[c]);
5881  assert(consdata != NULL);
5882 
5883  /* the constraint must be an equality constraint */
5884  if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5885  continue;
5886 
5887  /* the root expression needs to be a sum expression */
5888  if( !SCIPisExprSum(scip, consdata->expr) )
5889  continue;
5890 
5891  children = SCIPexprGetChildren(consdata->expr);
5892  nchildren = SCIPexprGetNChildren(consdata->expr);
5893 
5894  /* the sum expression must have at least two children
5895  * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5896  */
5897  if( nchildren <= 1 )
5898  continue;
5899 
5900  coefs = SCIPgetCoefsExprSum(consdata->expr);
5901 
5902  /* find first continuous variable and get value of its coefficient */
5903  for( i = 0; i < nchildren; ++i )
5904  {
5905  if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5906  continue;
5907 
5908  candcoef = coefs[i];
5909  assert(candcoef != 0.0);
5910 
5911  /* lhs/rhs - constant divided by candcoef must be integral
5912  * if not, break with cand == NULL, so give up
5913  */
5914  if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5915  cand = children[i];
5916 
5917  break;
5918  }
5919 
5920  /* no suitable continuous variable found */
5921  if( cand == NULL )
5922  continue;
5923 
5924  /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5925  for( i = 0; i < nchildren; ++i )
5926  {
5927  if( children[i] == cand )
5928  continue;
5929 
5930  /* child i must be integral */
5931  if( !SCIPexprIsIntegral(children[i]) )
5932  {
5933  cand = NULL;
5934  break;
5935  }
5936 
5937  /* coefficient of child i must be integral if diving by candcoef */
5938  if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5939  {
5940  cand = NULL;
5941  break;
5942  }
5943  }
5944 
5945  if( cand == NULL )
5946  continue;
5947 
5948  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5950 
5951  /* change variable type */
5952  SCIP_CALL( SCIPchgVarType(scip, SCIPgetVarExprVar(cand), SCIP_VARTYPE_IMPLINT, infeasible) );
5953 
5954  if( *infeasible )
5955  return SCIP_OKAY;
5956 
5957  /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5959  }
5960 
5961  return SCIP_OKAY;
5962 }
5963 
5964 /** creates auxiliary variable for a given expression
5965  *
5966  * @note for a variable expression it does nothing
5967  * @note this function can only be called in stage SCIP_STAGE_SOLVING
5968  */
5969 static
5971  SCIP* scip, /**< SCIP data structure */
5972  SCIP_EXPR* expr /**< expression */
5973  )
5974 {
5975  SCIP_EXPR_OWNERDATA* ownerdata;
5976  SCIP_CONSHDLRDATA* conshdlrdata;
5977  SCIP_VARTYPE vartype;
5978  SCIP_INTERVAL activity;
5979  char name[SCIP_MAXSTRLEN];
5980 
5981  assert(scip != NULL);
5982  assert(expr != NULL);
5983 
5984  ownerdata = SCIPexprGetOwnerData(expr);
5985  assert(ownerdata != NULL);
5986  assert(ownerdata->nauxvaruses > 0);
5987 
5988  /* if we already have auxvar, then do nothing */
5989  if( ownerdata->auxvar != NULL )
5990  return SCIP_OKAY;
5991 
5992  /* if expression is a variable-expression, then do nothing */
5993  if( SCIPisExprVar(scip, expr) )
5994  return SCIP_OKAY;
5995 
5996  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
5997  {
5998  SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
5999  return SCIP_INVALIDCALL;
6000  }
6001 
6002  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6003  assert(conshdlrdata != NULL);
6004  assert(conshdlrdata->auxvarid >= 0);
6005 
6006  /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6007  * but it usually indicates a missing simplify
6008  * if we find situations where we need to have an auxvar for a constant, then remove this assert
6009  */
6010  assert(!SCIPisExprValue(scip, expr));
6011 
6012  /* create and capture auxiliary variable */
6013  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6014  ++conshdlrdata->auxvarid;
6015 
6016  /* type of auxiliary variable depends on integrality information of the expression */
6018 
6019  /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6020  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6021  {
6022  activity = SCIPexprGetActivity(expr);
6023  /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6024  * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6025  * and abort in debug mode only
6026  */
6028  {
6029  SCIPABORT();
6031  }
6032  }
6033  else
6035 
6036  /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6037  * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6038  */
6039  if( SCIPgetDepth(scip) == 0 )
6040  {
6041  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
6042  }
6043  else
6044  {
6045  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
6046  }
6047 
6048  /* mark the auxiliary variable to be added for the relaxation only
6049  * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6050  * or to copy the variable to a subscip
6051  */
6052  SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6053 
6054  SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6055 
6056  SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6057 
6058  /* add variable locks in both directions
6059  * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6060  * but then we need to also update the auxvars locks when the expr locks change
6061  */
6062  SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6063 
6064 #ifdef WITH_DEBUG_SOLUTION
6065  if( SCIPdebugIsMainscip(scip) )
6066  {
6067  /* store debug solution value of auxiliary variable
6068  * assumes that expression has been evaluated in debug solution before
6069  */
6070  SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6071  }
6072 #endif
6073 
6074  if( SCIPgetDepth(scip) > 0 )
6075  {
6076  /* initialize local bounds to (locally valid) activity */
6077  SCIP_Bool cutoff;
6078  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6079  assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6080  }
6081 
6082  return SCIP_OKAY;
6083 }
6084 
6085 /** initializes separation for constraint
6086  *
6087  * - ensures that activities are up to date in all expressions
6088  * - creates auxiliary variables where required
6089  * - calls propExprDomains() to possibly tighten auxvar bounds
6090  * - calls separation initialization callback of nlhdlrs
6091  */
6092 static
6094  SCIP* scip, /**< SCIP data structure */
6095  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6096  SCIP_CONS** conss, /**< constraints */
6097  int nconss, /**< number of constraints */
6098  SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6099  )
6100 {
6101  SCIP_CONSDATA* consdata;
6102  SCIP_CONSHDLRDATA* conshdlrdata;
6103  SCIP_EXPRITER* it;
6104  SCIP_EXPR* expr;
6105  SCIP_RESULT result;
6106  SCIP_VAR* auxvar;
6107  int nreductions = 0;
6108  int c, e;
6109 
6110  assert(scip != NULL);
6111  assert(conshdlr != NULL);
6112  assert(conss != NULL || nconss == 0);
6113  assert(nconss >= 0);
6114  assert(infeasible != NULL);
6115 
6116  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6117  assert(conshdlrdata != NULL);
6118 
6119  /* start with new propbounds (just to be sure, should not be needed) */
6120  ++conshdlrdata->curpropboundstag;
6121 
6122  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6124 
6125  /* first ensure activities are up to date and create auxvars */
6126  *infeasible = FALSE;
6127  for( c = 0; c < nconss; ++c )
6128  {
6129  assert(conss != NULL);
6130  assert(conss[c] != NULL);
6131 
6132  consdata = SCIPconsGetData(conss[c]);
6133  assert(consdata != NULL);
6134  assert(consdata->expr != NULL);
6135 
6136 #ifdef WITH_DEBUG_SOLUTION
6137  if( SCIPdebugIsMainscip(scip) )
6138  {
6139  SCIP_SOL* debugsol;
6140 
6141  SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6142 
6143  if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6144  {
6145  /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6146  * in createAuxVar()
6147  */
6148  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6149  }
6150  }
6151 #endif
6152 
6153  /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6154  SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6155 
6156  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6157  {
6158  if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6159  {
6160  SCIP_CALL( createAuxVar(scip, expr) );
6161  }
6162  }
6163 
6164  auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6165  if( auxvar != NULL )
6166  {
6167  SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6168  SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6169  /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6170  SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6171  if( *infeasible )
6172  {
6173  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6174  break;
6175  }
6176 
6177  SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6178  if( *infeasible )
6179  {
6180  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6181  break;
6182  }
6183  }
6184  }
6185 
6186  /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6187  * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6188  * (e.g., log(x*y), which becomes log(w), w=x*y
6189  * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6190  */
6191  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6192  if( result == SCIP_CUTOFF )
6193  *infeasible = TRUE;
6194 
6195  /* now call initsepa of nlhdlrs
6196  * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6197  * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6198  */
6200  for( c = 0; c < nconss && !*infeasible; ++c )
6201  {
6202  assert(conss != NULL);
6203  assert(conss[c] != NULL);
6204 
6205  consdata = SCIPconsGetData(conss[c]);
6206  assert(consdata != NULL);
6207  assert(consdata->expr != NULL);
6208 
6209  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6210  {
6211  SCIP_EXPR_OWNERDATA* ownerdata;
6212 
6213  ownerdata = SCIPexprGetOwnerData(expr);
6214  assert(ownerdata != NULL);
6215 
6216  if( ownerdata->nauxvaruses == 0 )
6217  continue;
6218 
6219  for( e = 0; e < ownerdata->nenfos; ++e )
6220  {
6221  SCIP_NLHDLR* nlhdlr;
6222  SCIP_Bool underestimate;
6223  SCIP_Bool overestimate;
6224  assert(ownerdata->enfos[e] != NULL);
6225 
6226  /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6227  * which participated in a previous initSepa() call
6228  */
6229  if( ownerdata->enfos[e]->issepainit )
6230  continue;
6231 
6232  /* only call initsepa if it will actually separate */
6233  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6234  continue;
6235 
6236  nlhdlr = ownerdata->enfos[e]->nlhdlr;
6237  assert(nlhdlr != NULL);
6238 
6239  /* only init sepa if there is an initsepa callback */
6240  if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6241  continue;
6242 
6243  /* check whether expression needs to be under- or overestimated */
6244  overestimate = ownerdata->nlocksneg > 0;
6245  underestimate = ownerdata->nlockspos > 0;
6246  assert(underestimate || overestimate);
6247 
6248  SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6249 
6250  /* call the separation initialization callback of the nonlinear handler */
6251  SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6252  ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6253  ownerdata->enfos[e]->issepainit = TRUE;
6254 
6255  if( *infeasible )
6256  {
6257  /* stop everything if we detected infeasibility */
6258  SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6259  break;
6260  }
6261  }
6262  }
6263  }
6264 
6265  SCIPfreeExpriter(&it);
6266 
6267  return SCIP_OKAY;
6268 }
6269 
6270 /** returns whether we are ok to branch on auxiliary variables
6271  *
6272  * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6273  */
6274 static
6276  SCIP* scip, /**< SCIP data structure */
6277  SCIP_CONSHDLR* conshdlr /**< constraint handler */
6278  )
6279 {
6280  SCIP_CONSHDLRDATA* conshdlrdata;
6281 
6282  assert(conshdlr != NULL);
6283 
6284  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6285  assert(conshdlrdata != NULL);
6286 
6287  return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6288 }
6289 
6290 /** gets weight of variable when splitting violation score onto several variables in an expression */
6291 static
6293  SCIP* scip, /**< SCIP data structure */
6294  SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6295  SCIP_VAR* var, /**< variable */
6296  SCIP_SOL* sol /**< current solution */
6297  )
6298 {
6299  SCIP_CONSHDLRDATA* conshdlrdata;
6300 
6301  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6302  assert(conshdlrdata != NULL);
6303 
6304  switch( conshdlrdata->branchviolsplit )
6305  {
6306  case 'u' : /* uniform: everyone gets the same score */
6307  return 1.0;
6308 
6309  case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6310  {
6311  SCIP_Real weight;
6312  weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6313  return MAX(0.05, weight);
6314  }
6315 
6316  case 'd' : /* domain width */
6317  return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6318 
6319  case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6320  {
6321  SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6322  assert(width > 0.0);
6323  if( width > 10.0 )
6324  return 10.0*log10(width);
6325  if( width < 0.1 )
6326  return 0.1/(-log10(width));
6327  return width;
6328  }
6329 
6330  default :
6331  SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6332  SCIPABORT();
6333  return SCIP_INVALID;
6334  }
6335 }
6336 
6337 /** adds violation-branching score to a set of expressions, thereby distributing the score
6338  *
6339  * Each expression must either be a variable expression or have an aux-variable.
6340  *
6341  * If unbounded variables are present, each unbounded var gets an even score.
6342  * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6343  */
6344 static
6345 void addExprsViolScore(
6346  SCIP* scip, /**< SCIP data structure */
6347  SCIP_EXPR** exprs, /**< expressions where to add branching score */
6348  int nexprs, /**< number of expressions */
6349  SCIP_Real violscore, /**< violation-branching score to add to expression */
6350  SCIP_SOL* sol, /**< current solution */
6351  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6352  )
6353 {
6354  SCIP_CONSHDLR* conshdlr;
6355  SCIP_VAR* var;
6356  SCIP_Real weight;
6357  SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6358  int nunbounded = 0; /* number of candidates with unbounded domain */
6359  int i;
6360 
6361  assert(exprs != NULL);
6362  assert(nexprs > 0);
6363  assert(success != NULL);
6364 
6365  if( nexprs == 1 )
6366  {
6367  SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6368  SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6370  *success = TRUE;
6371  return;
6372  }
6373 
6374  conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6375 
6376  for( i = 0; i < nexprs; ++i )
6377  {
6378  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6379  assert(var != NULL);
6380 
6381  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6382  ++nunbounded;
6383  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6384  weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6385  }
6386 
6387  *success = FALSE;
6388  for( i = 0; i < nexprs; ++i )
6389  {
6390  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6391  assert(var != NULL);
6392 
6393  if( nunbounded > 0 )
6394  {
6395  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6396  {
6397  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6398  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6399  100.0/nunbounded, violscore,
6401  *success = TRUE;
6402  }
6403  }
6404  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6405  {
6406  assert(weightsum > 0.0);
6407 
6408  weight = getViolSplitWeight(scip, conshdlr, var, sol);
6409  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6410  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6411  100*weight / weightsum, violscore,
6413  *success = TRUE;
6414  }
6415  else
6416  {
6417  SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6419  }
6420  }
6421 }
6422 
6423 /** adds violation-branching score to children of expression for given auxiliary variables
6424  *
6425  * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6426  * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6427  *
6428  * @note This method may modify the given auxvars array by means of sorting.
6429  */
6430 static
6432  SCIP* scip, /**< SCIP data structure */
6433  SCIP_EXPR* expr, /**< expression where to start searching */
6434  SCIP_Real violscore, /**< violation score to add to expression */
6435  SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6436  int nauxvars, /**< number of auxiliary variables */
6437  SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6438  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6439  )
6440 {
6441  SCIP_EXPRITER* it;
6442  SCIP_VAR* auxvar;
6443  SCIP_EXPR** exprs;
6444  int nexprs;
6445  int pos;
6446 
6447  assert(scip != NULL);
6448  assert(expr != NULL);
6449  assert(auxvars != NULL);
6450  assert(success != NULL);
6451 
6452  /* sort variables to make lookup below faster */
6453  SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6454 
6455  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6457 
6458  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6459  nexprs = 0;
6460 
6461  for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6462  {
6463  auxvar = SCIPgetExprAuxVarNonlinear(expr);
6464  if( auxvar == NULL )
6465  continue;
6466 
6467  /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6468  if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6469  {
6470  assert(auxvars[pos] == auxvar);
6471 
6472  SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6473  exprs[nexprs++] = expr;
6474 
6475  if( nexprs == nauxvars )
6476  break;
6477  }
6478  }
6479 
6480  SCIPfreeExpriter(&it);
6481 
6482  if( nexprs > 0 )
6483  {
6484  SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6485  }
6486  else
6487  *success = FALSE;
6488 
6489  SCIPfreeBufferArray(scip, &exprs);
6490 
6491  return SCIP_OKAY;
6492 }
6493 
6494 /** registers all unfixed variables in violated constraints as branching candidates */
6495 static
6497  SCIP* scip, /**< SCIP data structure */
6498  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6499  SCIP_CONS** conss, /**< constraints */
6500  int nconss, /**< number of constraints */
6501  int* nnotify /**< counter for number of notifications performed */
6502  )
6503 {
6504  SCIP_CONSDATA* consdata;
6505  SCIP_VAR* var;
6506  int c;
6507  int i;
6508 
6509  assert(conshdlr != NULL);
6510  assert(conss != NULL || nconss == 0);
6511  assert(nnotify != NULL);
6512 
6513  *nnotify = 0;
6514 
6515  for( c = 0; c < nconss; ++c )
6516  {
6517  assert(conss != NULL && conss[c] != NULL);
6518 
6519  consdata = SCIPconsGetData(conss[c]);
6520  assert(consdata != NULL);
6521 
6522  /* consider only violated constraints */
6523  if( !isConsViolated(scip, conss[c]) )
6524  continue;
6525 
6526  /* register all variables that have not been fixed yet */
6527  assert(consdata->varexprs != NULL);
6528  for( i = 0; i < consdata->nvarexprs; ++i )
6529  {
6530  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6531  assert(var != NULL);
6532 
6533  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6534  {
6536  ++(*nnotify);
6537  }
6538  }
6539  }
6540 
6541  return SCIP_OKAY;
6542 }
6543 
6544 /** registers all variables in violated constraints with branching scores as external branching candidates */
6545 static
6547  SCIP* scip, /**< SCIP data structure */
6548  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6549  SCIP_CONS** conss, /**< constraints */
6550  int nconss, /**< number of constraints */
6551  SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6552  )
6553 {
6554  SCIP_CONSDATA* consdata;
6555  SCIP_EXPRITER* it = NULL;
6556  int c;
6557 
6558  assert(conshdlr != NULL);
6559  assert(success != NULL);
6560 
6561  *success = FALSE;
6562 
6563  if( branchAuxNonlinear(scip, conshdlr) )
6564  {
6565  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6567  }
6568 
6569  /* register external branching candidates */
6570  for( c = 0; c < nconss; ++c )
6571  {
6572  assert(conss != NULL && conss[c] != NULL);
6573 
6574  consdata = SCIPconsGetData(conss[c]);
6575  assert(consdata != NULL);
6576  assert(consdata->varexprs != NULL);
6577 
6578  /* consider only violated constraints */
6579  if( !isConsViolated(scip, conss[c]) )
6580  continue;
6581 
6582  if( !branchAuxNonlinear(scip, conshdlr) )
6583  {
6584  int i;
6585 
6586  /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6587  * only, so we can loop over variable expressions
6588  */
6589  for( i = 0; i < consdata->nvarexprs; ++i )
6590  {
6591  SCIP_Real violscore;
6592  SCIP_Real lb;
6593  SCIP_Real ub;
6594  SCIP_VAR* var;
6595 
6596  violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6597 
6598  /* skip variable expressions that do not have a violation score */
6599  if( violscore == 0.0 )
6600  continue;
6601 
6602  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6603  assert(var != NULL);
6604 
6605  lb = SCIPvarGetLbLocal(var);
6606  ub = SCIPvarGetUbLocal(var);
6607 
6608  /* consider variable for branching if it has not been fixed yet */
6609  if( !SCIPisEQ(scip, lb, ub) )
6610  {
6611  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6612  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6613  *success = TRUE;
6614  }
6615  else
6616  {
6617  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6618  }
6619 
6620  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6621  * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6622  */
6623  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6624  }
6625  }
6626  else
6627  {
6628  SCIP_EXPR* expr;
6629  SCIP_VAR* var;
6630  SCIP_Real lb;
6631  SCIP_Real ub;
6632  SCIP_Real violscore;
6633 
6634  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6635  {
6636  violscore = SCIPgetExprViolScoreNonlinear(expr);
6637  if( violscore == 0.0 )
6638  continue;
6639 
6640  /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6641  * variable, so this expression should either be an original variable or have an auxiliary variable
6642  */
6643  var = SCIPgetExprAuxVarNonlinear(expr);
6644  assert(var != NULL);
6645 
6646  lb = SCIPvarGetLbLocal(var);
6647  ub = SCIPvarGetUbLocal(var);
6648 
6649  /* consider variable for branching if it has not been fixed yet */
6650  if( !SCIPisEQ(scip, lb, ub) )
6651  {
6652  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6653 
6654  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6655  *success = TRUE;
6656  }
6657  else
6658  {
6659  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6660  }
6661  }
6662  }
6663  }
6664 
6665  if( it != NULL )
6666  SCIPfreeExpriter(&it);
6667 
6668  return SCIP_OKAY;
6669 }
6670 
6671 /** collect branching candidates from violated constraints
6672  *
6673  * Fills array with expressions that serve as branching candidates.
6674  * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6675  * branching candidate.
6676  *
6677  * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6678  * through variable-expressions only.
6679  */
6680 static
6682  SCIP* scip, /**< SCIP data structure */
6683  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6684  SCIP_CONS** conss, /**< constraints to process */
6685  int nconss, /**< number of constraints */
6686  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6687  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6688  SCIP_Longint soltag, /**< tag of solution */
6689  BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6690  int* ncands /**< number of candidates found */
6691  )
6692 {
6693  SCIP_CONSHDLRDATA* conshdlrdata;
6694  SCIP_CONSDATA* consdata;
6695  SCIP_EXPRITER* it = NULL;
6696  int c;
6697  int attempt;
6698  SCIP_VAR* var;
6699 
6700  assert(scip != NULL);
6701  assert(conshdlr != NULL);
6702  assert(cands != NULL);
6703  assert(ncands != NULL);
6704 
6705  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6706  assert(conshdlrdata != NULL);
6707 
6708  if( branchAuxNonlinear(scip, conshdlr) )
6709  {
6710  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6712  }
6713 
6714  *ncands = 0;
6715  for( attempt = 0; attempt < 2; ++attempt )
6716  {
6717  /* collect branching candidates from violated constraints
6718  * in the first attempt, consider only constraints with large violation
6719  * in the second attempt, consider all remaining violated constraints
6720  */
6721  for( c = 0; c < nconss; ++c )
6722  {
6723  SCIP_Real consviol;
6724 
6725  assert(conss != NULL && conss[c] != NULL);
6726 
6727  /* consider only violated constraints */
6728  if( !isConsViolated(scip, conss[c]) )
6729  continue;
6730 
6731  consdata = SCIPconsGetData(conss[c]);
6732  assert(consdata != NULL);
6733  assert(consdata->varexprs != NULL);
6734 
6735  SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6736 
6737  if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6738  continue;
6739  else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6740  continue;
6741 
6742  if( !branchAuxNonlinear(scip, conshdlr) )
6743  {
6744  int i;
6745 
6746  /* if not branching on auxvars, then violation-branching scores will be available for original variables
6747  * only, so we can loop over variable expressions
6748  * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6749  * variable, therefore we invalidate the score of a variable after processing it.
6750  */
6751  for( i = 0; i < consdata->nvarexprs; ++i )
6752  {
6753  SCIP_Real lb;
6754  SCIP_Real ub;
6755 
6756  /* skip variable expressions that do not have a valid violation score */
6757  if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6758  continue;
6759 
6760  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6761  assert(var != NULL);
6762 
6763  lb = SCIPvarGetLbLocal(var);
6764  ub = SCIPvarGetUbLocal(var);
6765 
6766  /* skip already fixed variable */
6767  if( SCIPisEQ(scip, lb, ub) )
6768  {
6769  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6770  continue;
6771  }
6772 
6773  assert(*ncands + 1 < SCIPgetNVars(scip));
6774  cands[*ncands].expr = consdata->varexprs[i];
6775  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6776  ++(*ncands);
6777 
6778  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6779  * several times as external branching candidate */
6780  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6781  }
6782  }
6783  else
6784  {
6785  SCIP_EXPR* expr;
6786  SCIP_Real lb;
6787  SCIP_Real ub;
6788 
6789  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6790  {
6791  if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6792  continue;
6793 
6794  /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6795  * variables, so this expression should either be an original variable or have an auxiliary variable
6796  */
6797  var = SCIPgetExprAuxVarNonlinear(expr);
6798  assert(var != NULL);
6799 
6800  lb = SCIPvarGetLbLocal(var);
6801  ub = SCIPvarGetUbLocal(var);
6802 
6803  /* skip already fixed variable */
6804  if( SCIPisEQ(scip, lb, ub) )
6805  {
6806  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6807  continue;
6808  }
6809 
6810  assert(*ncands + 1 < SCIPgetNVars(scip));
6811  cands[*ncands].expr = expr;
6812  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6813  ++(*ncands);
6814  }
6815  }
6816  }
6817 
6818  /* if we have branching candidates, then we don't need another attempt */
6819  if( *ncands > 0 )
6820  break;
6821  }
6822 
6823  if( it != NULL )
6824  SCIPfreeExpriter(&it);
6825 
6826  return SCIP_OKAY;
6827 }
6828 
6829 /** computes a branching score for a variable that reflects how important branching on this variable would be for
6830  * improving the dual bound from the LP relaxation
6831  *
6832  * Assume the Lagrangian for the current LP is something of the form
6833  * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6834  * where x are the original variables, z the auxiliary variables,
6835  * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6836  *
6837  * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6838  * If we could have used not only an estimator, but the actual function f(x), then this would
6839  * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6840  * Using a lot of handwaving, we claim that
6841  * lambda_i * (f(x) - a_i'x + b_i)
6842  * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6843  * If an estimator depended on local bounds, then it could be improved by branching.
6844  * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6845  *
6846  * To score a variable, we then sum the values lambda_i * (f(x) - a_i'x + b_i) for all rows in which the variable appears.
6847  * To scale, we divide by the LP objective value (if >1).
6848  *
6849  * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6850  * these are affected by the bounds on original variables indirectly (through forward-propagation)
6851  *
6852  * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6853  * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6854  * would also be branching candidates
6855  */
6856 static
6858  SCIP* scip, /**< SCIP data structure */
6859  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6860  SCIP_VAR* var /**< variable */
6861  )
6862 {
6863  SCIP_COL* col;
6864  SCIP_ROW** rows;
6865  int nrows;
6866  int r;
6867  SCIP_Real dualscore;
6868 
6869  assert(scip != NULL);
6870  assert(conshdlr != NULL);
6871  assert(var != NULL);
6872 
6873  /* if LP not solved, then the dual branching score is not available */
6875  return 0.0;
6876 
6877  /* if var is not in the LP, then the dual branching score is not available */
6879  return 0.0;
6880 
6881  col = SCIPvarGetCol(var);
6882  assert(col != NULL);
6883 
6884  if( !SCIPcolIsInLP(col) )
6885  return 0.0;
6886 
6887  nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6888  rows = SCIPcolGetRows(col);
6889 
6890  /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6891 
6892  /* aggregate duals from all rows from consexpr with non-zero dual
6893  * TODO: this is a quick-and-dirty implementation, and not used by default
6894  * in the long run, this should be either removed or replaced by a proper implementation
6895  */
6896  dualscore = 0.0;
6897  for( r = 0; r < nrows; ++r )
6898  {
6899  SCIP_Real estimategap;
6900  const char* estimategapstr;
6901 
6902  /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6903  * these would typically be local, unless they are created at the root node
6904  * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6905  if( !SCIProwIsLocal(rows[r]) )
6906  continue;
6907  */
6908  if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6909  continue;
6910  if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6911  continue;
6912 
6913  estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6914  if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6915  continue;
6916  estimategap = atof(estimategapstr + 13);
6917  assert(estimategap >= 0.0);
6918  if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6919  estimategap = SCIPgetHugeValue(scip);
6920 
6921  /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6922  SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6923 
6924  dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6925  }
6926 
6927  /* divide by optimal value of LP for scaling */
6928  dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6929 
6930  return dualscore;
6931 }
6932 
6933 /** computes branching scores (including weighted score) for a set of candidates
6934  *
6935  * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6936  * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6937  *
6938  * For each score, compute the maximum over all candidates.
6939  *
6940  * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6941  * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6942  * score of all candidates.
6943  * Further divide by the sum of all weights where a score was available (even if the score was 0).
6944  *
6945  * For example:
6946  * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6947  * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6948  * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6949  * - Then the weighted scores for x will be (2.0 * 10.0/12.0 + 3.0 * 5.0/5.0) / (2.0 + 3.0) = 0.9333.
6950  * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6951  */
6952 static
6954  SCIP* scip, /**< SCIP data structure */
6955  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6956  BRANCHCAND* cands, /**< branching candidates */
6957  int ncands, /**< number of candidates */
6958  SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6959  )
6960 {
6961  SCIP_CONSHDLRDATA* conshdlrdata;
6962  BRANCHCAND maxscore;
6963  int c;
6964 
6965  assert(scip != NULL);
6966  assert(conshdlr != NULL);
6967  assert(cands != NULL);
6968  assert(ncands > 0);
6969 
6970  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6971  assert(conshdlrdata != NULL);
6972 
6973  /* initialize counts to 0 */
6974  memset(&maxscore, 0, sizeof(BRANCHCAND));
6975 
6976  for( c = 0; c < ncands; ++c )
6977  {
6978  if( conshdlrdata->branchviolweight > 0.0 )
6979  {
6980  /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6981  maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6982  }
6983 
6984  if( conshdlrdata->branchdomainweight > 0.0 )
6985  {
6986  SCIP_Real domainwidth;
6987  SCIP_VAR* var;
6988 
6989  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6990  assert(var != NULL);
6991 
6992  /* get domain width, taking infinity at 1e20 on purpose */
6993  domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6994 
6995  /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6996  * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
6997  * the idea is to penalize very large and very small domains
6998  */
6999  if( domainwidth >= 1.0 )
7000  cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7001  else
7002  cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
7003 
7004  maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7005  }
7006  else
7007  cands[c].domain = 0.0;
7008 
7009  if( conshdlrdata->branchdualweight > 0.0 )
7010  {
7011  SCIP_VAR* var;
7012 
7013  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7014  assert(var != NULL);
7015 
7016  cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7017  maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7018  }
7019 
7020  if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7021  {
7022  SCIP_VAR* var;
7023 
7024  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7025  assert(var != NULL);
7026 
7027  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
7028  cands[c].pscost = SCIP_INVALID;
7029  else
7030  {
7031  SCIP_Real brpoint;
7032  SCIP_Real pscostdown;
7033  SCIP_Real pscostup;
7034  char strategy;
7035 
7036  /* decide how to compute pseudo-cost scores
7037  * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7038  * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7039  */
7041  strategy = conshdlrdata->branchpscostupdatestrategy;
7042  else
7043  strategy = 'l';
7044 
7045  brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7046 
7047  /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7048  * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7049  * For here, I use a simple #counts >= branchpscostreliable.
7050  * TODO use SCIPgetVarPseudocostCount() instead?
7051  */
7052  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7053  {
7054  switch( strategy )
7055  {
7056  case 's' :
7057  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7058  break;
7059  case 'd' :
7060  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7061  break;
7062  case 'l' :
7063  if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7064  pscostdown = SCIP_INVALID;
7065  else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7066  pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7067  else
7068  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, NULL, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7069  break;
7070  default :
7071  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7072  pscostdown = SCIP_INVALID;
7073  }
7074  }
7075  else
7076  pscostdown = SCIP_INVALID;
7077 
7078  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7079  {
7080  switch( strategy )
7081  {
7082  case 's' :
7083  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7084  break;
7085  case 'd' :
7086  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7087  break;
7088  case 'l' :
7089  if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7090  pscostup = SCIP_INVALID;
7091  else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7092  pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7093  else
7094  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, NULL, var) );
7095  break;
7096  default :
7097  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7098  pscostup = SCIP_INVALID;
7099  }
7100  }
7101  else
7102  pscostup = SCIP_INVALID;
7103 
7104  /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7105  * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7106  */
7107  if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7108  cands[c].pscost = SCIP_INVALID;
7109  else if( pscostdown == SCIP_INVALID )
7110  cands[c].pscost = pscostup;
7111  else if( pscostup == SCIP_INVALID )
7112  cands[c].pscost = pscostdown;
7113  else
7114  cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7115  }
7116 
7117  if( cands[c].pscost != SCIP_INVALID )
7118  maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7119  }
7120 
7121  if( conshdlrdata->branchvartypeweight > 0.0 )
7122  {
7123  SCIP_VAR* var;
7124 
7125  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7126  assert(var != NULL);
7127 
7128  switch( SCIPvarGetType(var) )
7129  {
7130  case SCIP_VARTYPE_BINARY :
7131  cands[c].vartype = 1.0;
7132  break;
7133  case SCIP_VARTYPE_INTEGER :
7134  cands[c].vartype = 0.1;
7135  break;
7136  case SCIP_VARTYPE_IMPLINT :
7137  cands[c].vartype = 0.01;
7138  break;
7140  default:
7141  cands[c].vartype = 0.0;
7142  }
7143  maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7144  }
7145  }
7146 
7147  /* now compute a weighted score for each candidate from the single scores
7148  * the single scores are scaled to be in [0,1] for this
7149  */
7150  for( c = 0; c < ncands; ++c )
7151  {
7152  SCIP_Real weightsum;
7153 
7154  ENFOLOG(
7155  SCIP_VAR* var;
7156  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7157  SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7158  )
7159 
7160  cands[c].weighted = 0.0;
7161  weightsum = 0.0;
7162 
7163  if( maxscore.auxviol > 0.0 )
7164  {
7165  cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7166  weightsum += conshdlrdata->branchviolweight;
7167 
7168  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7169  }
7170 
7171  if( maxscore.domain > 0.0 )
7172  {
7173  cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7174  weightsum += conshdlrdata->branchdomainweight;
7175 
7176  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7177  }
7178 
7179  if( maxscore.dual > 0.0 )
7180  {
7181  cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7182  weightsum += conshdlrdata->branchdualweight;
7183 
7184  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7185  }
7186 
7187  if( maxscore.pscost > 0.0 )
7188  {
7189  /* use pseudo-costs only if available */
7190  if( cands[c].pscost != SCIP_INVALID )
7191  {
7192  cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7193  weightsum += conshdlrdata->branchpscostweight;
7194 
7195  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7196  }
7197  else
7198  {
7199  /* do not add pscostscore, if not available, also do not add into weightsum */
7200  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7201  }
7202  }
7203 
7204  if( maxscore.vartype > 0.0 )
7205  {
7206  cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7207  weightsum += conshdlrdata->branchvartypeweight;
7208 
7209  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7210  }
7211  assert(weightsum > 0.0); /* we should have got at least one valid score */
7212  cands[c].weighted /= weightsum;
7213 
7214  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7215  }
7216 }
7217 
7218 /** compare two branching candidates by their weighted score
7219  *
7220  * if weighted score is equal, use variable index of (aux)var
7221  */
7222 static
7223 SCIP_DECL_SORTINDCOMP(branchcandCompare)
7225  BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7226 
7227  if( cands[ind1].weighted != cands[ind2].weighted )
7228  return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7229  else
7230  return SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind1].expr)) - SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind2].expr));
7231 }
7232 
7233 /** do branching or register branching candidates */
7234 static
7236  SCIP* scip, /**< SCIP data structure */
7237  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7238  SCIP_CONS** conss, /**< constraints to process */
7239  int nconss, /**< number of constraints */
7240  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7241  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7242  SCIP_Longint soltag, /**< tag of solution */
7243  SCIP_RESULT* result /**< pointer to store the result of branching */
7244  )
7245 {
7246  SCIP_CONSHDLRDATA* conshdlrdata;
7247  BRANCHCAND* cands;
7248  int ncands;
7249  SCIP_VAR* var;
7250  SCIP_NODE* downchild;
7251  SCIP_NODE* eqchild;
7252  SCIP_NODE* upchild;
7253 
7254  assert(conshdlr != NULL);
7255  assert(result != NULL);
7256 
7257  *result = SCIP_DIDNOTFIND;
7258 
7259  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7260  assert(conshdlrdata != NULL);
7261 
7262  if( conshdlrdata->branchexternal )
7263  {
7264  /* just register branching candidates as external */
7265  SCIP_Bool success;
7266 
7267  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7268  if( success )
7269  *result = SCIP_INFEASIBLE;
7270 
7271  return SCIP_OKAY;
7272  }
7273 
7274  /* collect branching candidates and their auxviol-score */
7275  SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip)) );
7276  SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7277 
7278  /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7279  * we will return here and let the fallbacks in consEnfo() decide how to proceed
7280  */
7281  if( ncands == 0 )
7282  goto TERMINATE;
7283 
7284  if( ncands > 1 )
7285  {
7286  /* if there are more than one candidate, then compute scores and select */
7287  int* perm;
7288  int c;
7289  int left;
7290  int right;
7291  SCIP_Real threshold;
7292 
7293  /* compute additional scores on branching candidates and weighted score */
7294  scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7295 
7296  /* sort candidates by weighted score */
7297  SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7298  SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7299 
7300  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7301  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7302  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7303 
7304  /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7305  left = 0;
7306  right = ncands - 1;
7307  threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7308  while( left < right )
7309  {
7310  int mid = (left + right) / 2;
7311  if( cands[perm[mid]].weighted >= threshold )
7312  left = mid + 1;
7313  else
7314  right = mid;
7315  }
7316  assert(left <= ncands);
7317 
7318  if( left < ncands )
7319  {
7320  if( cands[perm[left]].weighted >= threshold )
7321  {
7322  assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7323  ncands = left + 1;
7324  }
7325  else
7326  {
7327  assert(cands[perm[left]].weighted < threshold);
7328  ncands = left;
7329  }
7330  }
7331  assert(ncands > 0);
7332 
7333  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7334  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7335  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7336 
7337  if( ncands > 1 )
7338  {
7339  /* choose at random from candidates 0..ncands-1 */
7340  if( conshdlrdata->branchrandnumgen == NULL )
7341  {
7342  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7343  }
7344  c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7345  var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7346  }
7347  else
7348  var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7349 
7350  SCIPfreeBufferArray(scip, &perm);
7351  }
7352  else
7353  {
7354  var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7355  }
7356  assert(var != NULL);
7357 
7358  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7359  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); )
7360 
7361  SCIP_CALL( SCIPbranchVarVal(scip, var, SCIPgetBranchingPoint(scip, var, SCIP_INVALID), &downchild, &eqchild,
7362  &upchild) );
7363  if( downchild != NULL || eqchild != NULL || upchild != NULL )
7364  *result = SCIP_BRANCHED;
7365  else
7366  /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7367  *result = SCIP_REDUCEDDOM;
7368 
7369  TERMINATE:
7370  SCIPfreeBufferArray(scip, &cands);
7371 
7372  return SCIP_OKAY;
7373 }
7374 
7375 /** call enforcement or estimate callback of nonlinear handler
7376  *
7377  * Calls the enforcement callback, if available.
7378  * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7379  *
7380  * If cut is weak, but estimator is not tight, tries to add branching candidates.
7381  */
7382 static
7384  SCIP* scip, /**< SCIP main data structure */
7385  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7386  SCIP_CONS* cons, /**< nonlinear constraint */
7387  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7388  SCIP_EXPR* expr, /**< expression */
7389  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7390  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7391  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7392  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7393  SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7394  SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7395  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7396  SCIP_RESULT* result /**< pointer to store the result */
7397  )
7398 {
7399  assert(result != NULL);
7400 
7401  /* call enforcement callback of the nlhdlr */
7402  SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7403  allowweakcuts, separated, inenforcement, result) );
7404 
7405  /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7406  if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7407  {
7408  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr %s succeeded with result %d\n",
7409  SCIPnlhdlrGetName(nlhdlr), *result); )
7410  return SCIP_OKAY;
7411  }
7412  else
7413  {
7414  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7415  }
7416 
7417  *result = SCIP_DIDNOTFIND;
7418 
7419  /* now call the estimator callback of the nlhdlr */
7420  if( SCIPnlhdlrHasEstimate(nlhdlr) )
7421  {
7422  SCIP_VAR* auxvar;
7423  SCIP_Bool sepasuccess = FALSE;
7424  SCIP_Bool branchscoresuccess = FALSE;
7425  SCIP_PTRARRAY* rowpreps;
7426  int minidx;
7427  int maxidx;
7428  int r;
7429  SCIP_ROWPREP* rowprep;
7430 
7431  SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7432 
7433  auxvar = SCIPgetExprAuxVarNonlinear(expr);
7434  assert(auxvar != NULL);
7435 
7436  SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7437  SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7438 
7439  minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7440  maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7441 
7442  assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7443 
7444  if( !sepasuccess )
7445  {
7446  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7447  SCIPnlhdlrGetName(nlhdlr)); )
7448  }
7449 
7450  for( r = minidx; r <= maxidx; ++r )
7451  {
7452  rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7453 
7454  assert(rowprep != NULL);
7455  assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7456 
7457  /* complete estimator to cut */
7458  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7459 
7460  /* add the cut and/or branching scores */
7461  SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7462  auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7463 
7464  SCIPfreeRowprep(scip, &rowprep);
7465  }
7466 
7467  SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7468  }
7469 
7470  return SCIP_OKAY;
7471 }
7472 
7473 /** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7474  *
7475  * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7476  */
7477 static
7479  SCIP* scip, /**< SCIP data structure */
7480  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7481  SCIP_CONS* cons, /**< nonlinear constraint */
7482  SCIP_EXPR* expr, /**< expression */
7483  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7484  SCIP_Longint soltag, /**< tag of solution */
7485  SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7486  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7487  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7488  )
7489 {
7490  SCIP_CONSHDLRDATA* conshdlrdata;
7491  SCIP_EXPR_OWNERDATA* ownerdata;
7492  SCIP_Real origviol;
7493  SCIP_Bool underestimate;
7494  SCIP_Bool overestimate;
7495  SCIP_Real auxviol;
7496  SCIP_Bool auxunderestimate;
7497  SCIP_Bool auxoverestimate;
7498  SCIP_RESULT hdlrresult;
7499  int e;
7500 
7501  assert(scip != NULL);
7502  assert(expr != NULL);
7503  assert(result != NULL);
7504 
7505  ownerdata = SCIPexprGetOwnerData(expr);
7506  assert(ownerdata != NULL);
7507  assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7508 
7509  *result = SCIP_DIDNOTFIND;
7510 
7511  /* make sure that this expression has been evaluated */
7512  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7513 
7514  /* decide whether under- or overestimate is required and get amount of violation */
7515  origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7516 
7517  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7518  assert(conshdlrdata != NULL);
7519 
7520  /* no sufficient violation w.r.t. the original variables -> skip expression */
7521  if( !overestimate && !underestimate )
7522  {
7523  return SCIP_OKAY;
7524  }
7525 
7526  /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7527  for( e = 0; e < ownerdata->nenfos; ++e )
7528  {
7529  SCIP_NLHDLR* nlhdlr;
7530 
7531  /* skip nlhdlr that do not want to participate in any separation */
7532  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7533  continue;
7534 
7535  nlhdlr = ownerdata->enfos[e]->nlhdlr;
7536  assert(nlhdlr != NULL);
7537 
7538  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7539  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7540  ENFOLOG(
7541  SCIPinfoMessage(scip, enfologfile, " expr ");
7542  SCIPprintExpr(scip, expr, enfologfile);
7543  SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7544  "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7545  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7546  )
7547 
7548  /* TODO if expr is root of constraint (consdata->expr == expr),
7549  * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7550  * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7551  * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7552  * so we should enforce in these auxiliaries first
7553  * if changing this here, we must also adapt analyzeViolation()
7554  */
7555 
7556  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7557  assert(auxviol >= 0.0);
7558 
7559  /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7560  if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7561  {
7562  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7563  "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7564  SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7565 
7566  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7567  continue;
7568  }
7569 
7570  /* if aux-violation is small (below feastol) and we look only for strong cuts, then it's unlikely to give a strong cut, so skip it */
7571  if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7572  {
7573  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7574  "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7575  underestimate, overestimate); )
7576 
7577  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7578  continue;
7579  }
7580 
7581  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7582  "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7583  auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7584 
7585  /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7586  * wants to be called for separation on this side, then call separation of nlhdlr
7587  */
7588  if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7589  {
7590  /* call the separation or estimation callback of the nonlinear handler for overestimation */
7591  hdlrresult = SCIP_DIDNOTFIND;
7592  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7593  ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7594 
7595  if( hdlrresult == SCIP_CUTOFF )
7596  {
7597  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7598  *result = SCIP_CUTOFF;
7599  ownerdata->lastenforced = conshdlrdata->enforound;
7600  break;
7601  }
7602 
7603  if( hdlrresult == SCIP_SEPARATED )
7604  {
7605  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7606  *result = SCIP_SEPARATED;
7607  ownerdata->lastenforced = conshdlrdata->enforound;
7608  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7609  break;
7610  }
7611 
7612  if( hdlrresult == SCIP_REDUCEDDOM )
7613  {
7614  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7615  *result = SCIP_REDUCEDDOM;
7616  ownerdata->lastenforced = conshdlrdata->enforound;
7617  /* TODO or should we always just stop here? */
7618  }
7619 
7620  if( hdlrresult == SCIP_BRANCHED )
7621  {
7622  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7623  assert(inenforcement);
7624 
7625  /* separation and domain reduction takes precedence over branching */
7626  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7627  if( *result == SCIP_DIDNOTFIND )
7628  *result = SCIP_BRANCHED;
7629  ownerdata->lastenforced = conshdlrdata->enforound;
7630  }
7631  }
7632 
7633  /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7634  * wants to be called for separation on this side, then call separation of nlhdlr
7635  */
7636  if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7637  {
7638  /* call the separation or estimation callback of the nonlinear handler for underestimation */
7639  hdlrresult = SCIP_DIDNOTFIND;
7640  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7641  ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7642 
7643  if( hdlrresult == SCIP_CUTOFF )
7644  {
7645  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7646  *result = SCIP_CUTOFF;
7647  ownerdata->lastenforced = conshdlrdata->enforound;
7648  break;
7649  }
7650 
7651  if( hdlrresult == SCIP_SEPARATED )
7652  {
7653  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7654  *result = SCIP_SEPARATED;
7655  ownerdata->lastenforced = conshdlrdata->enforound;
7656  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7657  break;
7658  }
7659 
7660  if( hdlrresult == SCIP_REDUCEDDOM )
7661  {
7662  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7663  *result = SCIP_REDUCEDDOM;
7664  ownerdata->lastenforced = conshdlrdata->enforound;
7665  /* TODO or should we always just stop here? */
7666  }
7667 
7668  if( hdlrresult == SCIP_BRANCHED )
7669  {
7670  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7671  assert(inenforcement);
7672 
7673  /* separation takes precedence over branching */
7674  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7675  if( *result == SCIP_DIDNOTFIND )
7676  *result = SCIP_BRANCHED;
7677  ownerdata->lastenforced = conshdlrdata->enforound;
7678  }
7679  }
7680  }
7681 
7682  return SCIP_OKAY;
7683 }
7684 
7685 /** helper function to enforce a single constraint */
7686 static
7688  SCIP* scip, /**< SCIP data structure */
7689  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7690  SCIP_CONS* cons, /**< constraint to process */
7691  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7692  SCIP_Longint soltag, /**< tag of solution */
7693  SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7694  SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7695  SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7696  SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7697  SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7698  )
7699 {
7700  SCIP_CONSDATA* consdata;
7701  SCIP_CONSHDLRDATA* conshdlrdata;
7702  SCIP_EXPR* expr;
7703 
7704  assert(conshdlr != NULL);
7705  assert(cons != NULL);
7706  assert(it != NULL);
7707  assert(result != NULL);
7708  assert(success != NULL);
7709 
7710  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7711  assert(conshdlrdata != NULL);
7712 
7713  consdata = SCIPconsGetData(cons);
7714  assert(consdata != NULL);
7715  assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7716 
7717  *success = FALSE;
7718 
7719  if( inenforcement && !consdata->ispropagated )
7720  {
7721  /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7722  * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7723  * (TODO: nlhdlr tells us now whether they do and so we could skip).
7724  * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7725  * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7726  * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7727  * confuse the stalling check for how long to do separation).
7728  */
7729  SCIP_Bool infeasible;
7730  int ntightenings;
7731 
7732  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7733  if( infeasible )
7734  {
7735  *result = SCIP_CUTOFF;
7736  return SCIP_OKAY;
7737  }
7738  /* if we tightened an auxvar bound, we better communicate that */
7739  if( ntightenings > 0 )
7740  *result = SCIP_REDUCEDDOM;
7741  }
7742 
7743  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7744  {
7745  SCIP_EXPR_OWNERDATA* ownerdata;
7746  SCIP_RESULT resultexpr;
7747 
7748  ownerdata = SCIPexprGetOwnerData(expr);
7749  assert(ownerdata != NULL);
7750 
7751  /* we can only enforce if there is an auxvar to compare with */
7752  if( ownerdata->auxvar == NULL )
7753  continue;
7754 
7755  assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7756  if( ownerdata->lastenforced == conshdlrdata->enforound )
7757  {
7758  ENFOLOG(
7759  SCIPinfoMessage(scip, enfologfile, " skip expr ");
7760  SCIPprintExpr(scip, expr, enfologfile);
7761  SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7762  )
7763  *success = TRUE;
7764  continue;
7765  }
7766 
7767  SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7768 
7769  /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7770  assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7771  if( ownerdata->lastenforced == conshdlrdata->enforound )
7772  *success = TRUE;
7773 
7774  if( resultexpr == SCIP_CUTOFF )
7775  {
7776  *result = SCIP_CUTOFF;
7777  break;
7778  }
7779 
7780  if( resultexpr == SCIP_SEPARATED )
7781  *result = SCIP_SEPARATED;
7782 
7783  if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7784  *result = SCIP_REDUCEDDOM;
7785 
7786  if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7787  *result = SCIP_BRANCHED;
7788  }
7789 
7790  return SCIP_OKAY;
7791 }
7792 
7793 /** try to separate violated constraints and, if in enforcement, register branching scores
7794  *
7795  * Sets result to
7796  * - SCIP_DIDNOTFIND, if nothing of the below has been done
7797  * - SCIP_CUTOFF, if node can be cutoff,
7798  * - SCIP_SEPARATED, if a cut has been added,
7799  * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7800  * - SCIP_BRANCHED, if branching has been done,
7801  * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7802  * - SCIP_INFEASIBLE, if external branching candidates were registered
7803  */
7804 static
7806  SCIP* scip, /**< SCIP data structure */
7807  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7808  SCIP_CONS** conss, /**< constraints to process */
7809  int nconss, /**< number of constraints */
7810  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7811  SCIP_Longint soltag, /**< tag of solution */
7812  SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7813  SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7814  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7815  )
7816 {
7817  SCIP_CONSHDLRDATA* conshdlrdata;
7818  SCIP_EXPRITER* it;
7819  SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7820  int c;
7821 
7822  assert(conshdlr != NULL);
7823  assert(conss != NULL || nconss == 0);
7824  assert(result != NULL);
7825 
7826  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7827  assert(conshdlrdata != NULL);
7828 
7829  /* increase tag to tell whether branching scores in expression belong to this sweep
7830  * and which expressions have already been enforced in this sweep
7831  * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7832  */
7833  ++(conshdlrdata->enforound);
7834 
7835  *result = SCIP_DIDNOTFIND;
7836 
7837  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7839 
7840  for( c = 0; c < nconss; ++c )
7841  {
7842  assert(conss != NULL && conss[c] != NULL);
7843 
7844  /* skip constraints that are not enabled or deleted */
7845  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7846  continue;
7847  assert(SCIPconsIsActive(conss[c]));
7848 
7849  /* skip constraints that have separation disabled if we are only in separation */
7850  if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7851  continue;
7852 
7853  /* skip non-violated constraints */
7854  if( !isConsViolated(scip, conss[c]) )
7855  continue;
7856 
7857  ENFOLOG(
7858  {
7859  SCIP_CONSDATA* consdata;
7860  int i;
7861  consdata = SCIPconsGetData(conss[c]);
7862  assert(consdata != NULL);
7863  SCIPinfoMessage(scip, enfologfile, " constraint ");
7864  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7865  SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7866  for( i = 0; i < consdata->nvarexprs; ++i )
7867  {
7868  SCIP_VAR* var;
7869  var = SCIPgetVarExprVar(consdata->varexprs[i]);
7870  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7871  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7872  }
7873  })
7874 
7875  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, result, &consenforced) );
7876 
7877  if( *result == SCIP_CUTOFF )
7878  break;
7879 
7880  if( !consenforced && inenforcement )
7881  {
7882  SCIP_Real viol;
7883 
7884  SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7885  if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7886  {
7887  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7888  "cuts allowed\n", SCIPconsGetName(conss[c])); )
7889 
7890  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, result, &consenforced) );
7891 
7892  if( consenforced )
7893  ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7894 
7895  if( *result == SCIP_CUTOFF )
7896  break;
7897  }
7898  }
7899  }
7900 
7901  SCIPfreeExpriter(&it);
7902 
7903  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7904 
7905  /* if having branching scores, then propagate them from expressions with children to variable expressions */
7906  if( *result == SCIP_BRANCHED )
7907  {
7908  /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7909  * branching
7910  */
7911  SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7912 
7913  /* branching should either have branched: result == SCIP_BRANCHED,
7914  * or fixed a variable: result == SCIP_REDUCEDDOM,
7915  * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7916  * or have not done anything: result == SCIP_DIDNOTFIND
7917  */
7918  assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7919  }
7920 
7921  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7922 
7923  return SCIP_OKAY;
7924 }
7925 
7926 /** collect (and print (if debugging enfo)) information on violation in expressions
7927  *
7928  * assumes that constraint violations have been computed
7929  */
7930 static
7932  SCIP* scip, /**< SCIP data structure */
7933  SCIP_CONS** conss, /**< constraints */
7934  int nconss, /**< number of constraints */
7935  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7936  SCIP_Longint soltag, /**< tag of solution */
7937  SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
7938  SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
7939  SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
7940  SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7941  SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
7942  )
7943 {
7944  SCIP_CONSDATA* consdata;
7945  SCIP_EXPRITER* it;
7946  SCIP_EXPR* expr;
7947  SCIP_Real v;
7948  int c;
7949 
7950  assert(conss != NULL || nconss == 0);
7951  assert(maxabsconsviol != NULL);
7952  assert(maxrelconsviol != NULL);
7953  assert(maxauxviol != NULL);
7954  assert(maxvarboundviol != NULL);
7955 
7956  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7958 
7959  *maxabsconsviol = 0.0;
7960  *maxrelconsviol = 0.0;
7961  *minauxviol = SCIPinfinity(scip);
7962  *maxauxviol = 0.0;
7963  *maxvarboundviol = 0.0;
7964 
7965  for( c = 0; c < nconss; ++c )
7966  {
7967  assert(conss != NULL && conss[c] != NULL);
7968 
7969  consdata = SCIPconsGetData(conss[c]);
7970  assert(consdata != NULL);
7971 
7972  /* skip constraints that are not enabled, deleted, or have separation disabled */
7973  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7974  continue;
7975  assert(SCIPconsIsActive(conss[c]));
7976 
7977  v = getConsAbsViolation(conss[c]);
7978  *maxabsconsviol = MAX(*maxabsconsviol, v);
7979 
7980  /* skip non-violated constraints */
7981  if( !isConsViolated(scip, conss[c]) )
7982  continue;
7983 
7984  SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
7985  *maxrelconsviol = MAX(*maxrelconsviol, v);
7986 
7987  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7988  {
7989  SCIP_EXPR_OWNERDATA* ownerdata;
7990  SCIP_Real auxvarvalue;
7991  SCIP_Real auxvarlb;
7992  SCIP_Real auxvarub;
7993  SCIP_Bool violunder;
7994  SCIP_Bool violover;
7995  SCIP_Real origviol;
7996  SCIP_Real auxviol;
7997  int e;
7998 
7999  ownerdata = SCIPexprGetOwnerData(expr);
8000  assert(ownerdata != NULL);
8001 
8002  if( ownerdata->auxvar == NULL )
8003  {
8004  /* check violation of variable bounds of original variable */
8005  if( SCIPisExprVar(scip, expr) )
8006  {
8007  SCIP_VAR* var;
8008  var = SCIPgetVarExprVar(expr);
8009  auxvarvalue = SCIPgetSolVal(scip, sol, var);
8010  auxvarlb = SCIPvarGetLbLocal(var);
8011  auxvarub = SCIPvarGetUbLocal(var);
8012 
8013  origviol = 0.0;
8014  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8015  origviol = auxvarlb - auxvarvalue;
8016  else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8017  origviol = auxvarvalue - auxvarub;
8018  if( origviol <= 0.0 )
8019  continue;
8020 
8021  *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8022 
8023  ENFOLOG(
8024  SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8025  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8026  SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8027  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8028  SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8029  SCIPinfoMessage(scip, enfologfile, "\n");
8030  )
8031  }
8032 
8033  continue;
8034  }
8035 
8036  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8037  auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8038  auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8039 
8040  /* check violation of variable bounds of auxiliary variable */
8041  if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8042  *maxvarboundviol = auxvarlb - auxvarvalue;
8043  else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8044  *maxvarboundviol = auxvarvalue - auxvarub;
8045 
8046  origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8047 
8048  ENFOLOG(
8049  if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8050  {
8051  SCIPinfoMessage(scip, enfologfile, "expr ");
8052  SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8053  SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8054 
8055  SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8056  if( origviol > 0.0 )
8057  SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8058  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8059  SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8060  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8061  SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8062  SCIPinfoMessage(scip, enfologfile, "\n");
8063  }
8064  )
8065 
8066  /* no violation w.r.t. the original variables -> skip expression */
8067  if( origviol == 0.0 )
8068  continue;
8069 
8070  /* compute aux-violation for each nonlinear handlers */
8071  for( e = 0; e < ownerdata->nenfos; ++e )
8072  {
8073  SCIP_NLHDLR* nlhdlr;
8074 
8075  /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8076  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8077  continue;
8078 
8079  nlhdlr = ownerdata->enfos[e]->nlhdlr;
8080  assert(nlhdlr != NULL);
8081 
8082  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8083  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8084 
8085  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8086 
8087  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8088 
8089  if( auxviol > 0.0 )
8090  {
8091  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8092  *maxauxviol = MAX(*maxauxviol, auxviol);
8093  *minauxviol = MIN(*minauxviol, auxviol);
8094  }
8095  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8096  }
8097  }
8098  }
8099 
8100  SCIPfreeExpriter(&it);
8101 
8102  return SCIP_OKAY;
8103 } /*lint !e715*/
8104 
8105 /** enforcement of constraints called by enfolp and enforelax */
8106 static
8108  SCIP* scip, /**< SCIP data structure */
8109  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8110  SCIP_CONS** conss, /**< constraints to process */
8111  int nconss, /**< number of constraints */
8112  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8113  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8114  )
8115 {
8116  SCIP_CONSHDLRDATA* conshdlrdata;
8117  SCIP_Real maxabsconsviol;
8118  SCIP_Real maxrelconsviol;
8119  SCIP_Real minauxviol;
8120  SCIP_Real maxauxviol;
8121  SCIP_Real maxvarboundviol;
8122  SCIP_Longint soltag;
8123  int nnotify;
8124  int c;
8125 
8126  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8127  assert(conshdlr != NULL);
8128 
8129  soltag = SCIPgetExprNewSoltag(scip);
8130 
8131  *result = SCIP_FEASIBLE;
8132  for( c = 0; c < nconss; ++c )
8133  {
8134  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8135 
8136  if( isConsViolated(scip, conss[c]) )
8137  *result = SCIP_INFEASIBLE;
8138  }
8139 
8140  if( *result == SCIP_FEASIBLE )
8141  {
8142  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8144  return SCIP_OKAY;
8145  }
8146 
8147  SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8148  &minauxviol, &maxauxviol, &maxvarboundviol) );
8149 
8150  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8151  "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8152  SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8153  maxvarboundviol, SCIPgetLPFeastol(scip)); )
8154 
8155  assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8156 
8157  /* try to propagate */
8158  if( conshdlrdata->propinenforce )
8159  {
8160  SCIP_RESULT propresult;
8161  int nchgbds = 0;
8162 
8163  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8164 
8165  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8166  {
8167  *result = propresult;
8168  return SCIP_OKAY;
8169  }
8170  }
8171 
8172  /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8173  * all violated expr/auxvar in violated constraints)
8174  */
8175  if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8176  sol == NULL )
8177  {
8178  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8179  ++conshdlrdata->ntightenlp;
8180 
8181  *result = SCIP_SOLVELP;
8182 
8183  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8184  "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8185 
8186  return SCIP_OKAY;
8187  }
8188 
8189  /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8190  * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8191  */
8192  if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8193  {
8194  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8195  ++conshdlrdata->ntightenlp;
8196 
8197  *result = SCIP_SOLVELP;
8198 
8199  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8200 
8201  return SCIP_OKAY;
8202  }
8203 
8204  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8205 
8206  if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8207  *result == SCIP_INFEASIBLE )
8208  return SCIP_OKAY;
8209 
8210  assert(*result == SCIP_DIDNOTFIND);
8211 
8212  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8213  "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8214 
8215  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8216  {
8217  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8218  ++conshdlrdata->ntightenlp;
8219 
8220  *result = SCIP_SOLVELP;
8221 
8222  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8223  "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8224 
8225  return SCIP_OKAY;
8226  }
8227 
8228  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8229  SCIPgetLPFeastol(scip)) && sol == NULL )
8230  {
8231  /* try whether tighten the LP feasibility tolerance could help
8232  * maybe it is just some cut that hasn't been taken into account sufficiently
8233  * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8234  * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8235  * until the LP feastol reaches epsilon
8236  * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8237  * when maxauxviol is above LP feastol)
8238  */
8239  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8240  ++conshdlrdata->ndesperatetightenlp;
8241 
8242  *result = SCIP_SOLVELP;
8243 
8244  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8245 
8246  return SCIP_OKAY;
8247  }
8248 
8249  /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8250  if( !conshdlrdata->propinenforce )
8251  {
8252  SCIP_RESULT propresult;
8253  int nchgbds = 0;
8254 
8255  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8256 
8257  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8258  {
8259  *result = propresult;
8260  return SCIP_OKAY;
8261  }
8262  }
8263 
8264  /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8265  * now look if we find any unfixed variable that we could still branch on
8266  */
8267  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8268 
8269  if( nnotify > 0 )
8270  {
8271  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8272  ++conshdlrdata->ndesperatebranch;
8273 
8274  *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8275 
8276  return SCIP_OKAY;
8277  }
8278 
8279  /* if everything is fixed in violated constraints, then let's cut off the node
8280  * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8281  * result may not be conclusive (when constraint violations are small)
8282  * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8283  * sufficiently (see st_e40)
8284  * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8285  * not "desperate", but a pretty obvious thing to do
8286  */
8287  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8288  *result = SCIP_CUTOFF;
8289 
8290  /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8291  if( !SCIPisZero(scip, maxvarboundviol) )
8292  ++conshdlrdata->ndesperatecutoff;
8293 
8294  return SCIP_OKAY;
8295 }
8296 
8297 /** separation for all violated constraints to be used by SEPA callbacks */
8298 static
8300  SCIP* scip, /**< SCIP data structure */
8301  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8302  SCIP_CONS** conss, /**< constraints to process */
8303  int nconss, /**< number of constraints */
8304  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8305  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8306  )
8307 {
8308  SCIP_Longint soltag;
8309  SCIP_Bool haveviol = FALSE;
8310  int c;
8311 
8312  *result = SCIP_DIDNOTFIND;
8313 
8314  soltag = SCIPgetExprNewSoltag(scip);
8315 
8316  /* compute violations */
8317  for( c = 0; c < nconss; ++c )
8318  {
8319  assert(conss[c] != NULL);
8320 
8321  /* skip constraints that are not enabled, deleted, or have separation disabled */
8322  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8323  continue;
8324  assert(SCIPconsIsActive(conss[c]));
8325 
8326  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8327 
8328  if( isConsViolated(scip, conss[c]) )
8329  haveviol = TRUE;
8330  }
8331 
8332  /* if none of our constraints are violated, don't attempt separation */
8333  if( !haveviol )
8334  {
8335  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8336  return SCIP_OKAY;
8337  }
8338 
8339  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8340 
8341  /* call separation */
8342  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8343 
8344  return SCIP_OKAY;
8345 }
8346 
8347 /** hash key retrieval function for bilinear term entries */
8348 static
8349 SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8350 { /*lint --e{715}*/
8351  SCIP_CONSHDLRDATA* conshdlrdata;
8352  int idx;
8353 
8354  conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8355  assert(conshdlrdata != NULL);
8356 
8357  idx = ((int)(size_t)elem) - 1;
8358  assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8359 
8360  return (void*)&conshdlrdata->bilinterms[idx];
8361 }
8362 
8363 /** returns TRUE iff the bilinear term entries are equal */
8364 static
8365 SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8366 { /*lint --e{715}*/
8369 
8370  /* get corresponding entries */
8371  entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8372  entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8373  assert(entry1->x != NULL && entry1->y != NULL);
8374  assert(entry2->x != NULL && entry2->y != NULL);
8375  assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8376  assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8377 
8378  return entry1->x == entry2->x && entry1->y == entry2->y;
8379 }
8380 
8381 /** returns the hash value of the key */
8382 static
8383 SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8384 { /*lint --e{715}*/
8386 
8388  assert(entry->x != NULL && entry->y != NULL);
8389  assert(SCIPvarCompare(entry->x, entry->y) < 1);
8390 
8391  return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8392 }
8393 
8394 /** compare two auxiliary expressions
8395  *
8396  * Compares auxiliary variables, followed by coefficients, and then constants.
8397  */
8398 static
8399 SCIP_DECL_SORTPTRCOMP(auxexprComp)
8403  int compvars;
8404  int i;
8405 
8406  /* compare the auxiliary variables */
8407  compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8408 
8409  if( compvars != 0 )
8410  return compvars;
8411 
8412  /* compare the coefficients and constants */
8413  for( i = 0; i < 3; ++i )
8414  {
8415  if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8416  return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8417  }
8418 
8419  return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8420 }
8421 
8422 /* add an auxiliary expression to a bilinear term */
8423 static
8425  SCIP* scip, /**< SCIP data structure */
8426  SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8427  SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8428  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8429  SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8430  )
8431 {
8432  SCIP_Bool found;
8433  int pos;
8434  int i;
8435 
8436  *added = FALSE;
8437 
8438  /* check if auxexpr has already been added to term */
8439  if( term->nauxexprs == 0 )
8440  {
8441  found = FALSE;
8442  pos = 0;
8443  }
8444  else
8445  {
8446  found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8447  }
8448 
8449  if( !found )
8450  {
8451  if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8452  return SCIP_OKAY;
8453 
8454  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8455  assert(term->auxexprssize >= term->nauxexprs + 1);
8456 
8457  /* insert expression at the correct position */
8458  for( i = term->nauxexprs; i > pos; --i )
8459  {
8460  term->aux.exprs[i] = term->aux.exprs[i-1];
8461  }
8462  term->aux.exprs[pos] = auxexpr;
8463  ++(term->nauxexprs);
8464  *added = TRUE;
8465  }
8466  else
8467  {
8468  term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8469  term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8470  }
8471 
8472  return SCIP_OKAY;
8473 }
8474 
8475 /** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8476 static
8478  SCIP* scip, /**< SCIP data structure */
8479  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8480  SCIP_CONS** conss, /**< nonlinear constraints */
8481  int nconss /**< total number of nonlinear constraints */
8482  )
8483 {
8484  SCIP_CONSHDLRDATA* conshdlrdata;
8485  SCIP_EXPRITER* it;
8486  int c;
8487 
8488  assert(conss != NULL || nconss == 0);
8489 
8490  if( nconss == 0 )
8491  return SCIP_OKAY;
8492 
8493  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8494  assert(conshdlrdata != NULL);
8495 
8496  /* check whether the bilinear terms have been stored already */
8497  if( conshdlrdata->bilinterms != NULL )
8498  return SCIP_OKAY;
8499 
8500  /* create and initialize iterator */
8501  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8504 
8505  /* iterate through all constraints */
8506  for( c = 0; c < nconss; ++c )
8507  {
8508  SCIP_CONSDATA* consdata;
8509  SCIP_EXPR* expr;
8510 
8511  assert(conss != NULL && conss[c] != NULL);
8512  consdata = SCIPconsGetData(conss[c]);
8513  assert(consdata != NULL);
8514 
8515  /* iterate through all expressions */
8516  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8517  {
8518  SCIP_EXPR** children = SCIPexprGetChildren(expr);
8519  SCIP_VAR* x = NULL;
8520  SCIP_VAR* y = NULL;
8521 
8522  /* check whether the expression is of the form f(..)^2 */
8523  if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8524  {
8525  x = SCIPgetExprAuxVarNonlinear(children[0]);
8526  y = x;
8527  }
8528  /* check whether the expression is of the form f(..) * g(..) */
8529  else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8530  {
8531  x = SCIPgetExprAuxVarNonlinear(children[0]);
8532  y = SCIPgetExprAuxVarNonlinear(children[1]);
8533  }
8534 
8535  /* add variables to the hash table */
8536  if( x != NULL && y != NULL )
8537  {
8540  }
8541  }
8542  }
8543 
8544  /* release iterator */
8545  SCIPfreeExpriter(&it);
8546 
8547  return SCIP_OKAY;
8548 }
8549 
8550 /** store x, y and the locks in a new bilinear term */
8551 static
8553  SCIP* scip, /**< SCIP data structure */
8554  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8555  SCIP_VAR* x, /**< the first variable */
8556  SCIP_VAR* y, /**< the second variable */
8557  int nlockspos, /**< number of positive locks of the bilinear term */
8558  int nlocksneg, /**< number of negative locks of the bilinear term */
8559  int* idx, /**< pointer to store the position of the term in bilinterms array */
8560  SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8561  )
8562 {
8563  SCIP_CONSHDLRDATA* conshdlrdata;
8565 
8566  assert(conshdlr != NULL);
8567  assert(x != NULL);
8568  assert(y != NULL);
8569  assert(nlockspos >= 0);
8570  assert(nlocksneg >= 0);
8571 
8572  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8573  assert(conshdlrdata != NULL);
8574 
8575  /* ensure that x.index <= y.index */
8576  if( SCIPvarCompare(x, y) == 1 )
8577  {
8578  SCIPswapPointers((void**)&x, (void**)&y);
8579  }
8580  assert(SCIPvarCompare(x, y) < 1);
8581 
8582  *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8583 
8584  /* update or create the term */
8585  if( *idx >= 0 )
8586  { /* the term has already been added */
8587  assert(conshdlrdata->bilinterms[*idx].x == x);
8588  assert(conshdlrdata->bilinterms[*idx].y == y);
8589 
8590  /* get term and add locks */
8591  term = &conshdlrdata->bilinterms[*idx];
8592  assert(existing <= term->existing); /* implicit terms are added after existing ones */
8593  term->nlockspos += nlockspos;
8594  term->nlocksneg += nlocksneg;
8595  }
8596  else
8597  { /* this is the first time we encounter this product */
8598  /* ensure size of bilinterms array */
8599  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8600 
8601  *idx = conshdlrdata->nbilinterms;
8602 
8603  /* get term and set values in the created bilinear term */
8604  term = &conshdlrdata->bilinterms[*idx];
8605  assert(term != NULL);
8606  term->x = x;
8607  term->y = y;
8608  term->nauxexprs = 0;
8609  term->auxexprssize = 0;
8610  term->nlockspos = nlockspos;
8611  term->nlocksneg = nlocksneg;
8612  term->existing = existing;
8613  if( existing )
8614  term->aux.var = NULL;
8615  else
8616  term->aux.exprs = NULL;
8617 
8618  /* increase the total number of bilinear terms */
8619  ++(conshdlrdata->nbilinterms);
8620 
8621  /* save to the hashtable */
8622  if( conshdlrdata->bilinhashtable == NULL )
8623  {
8624  SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8625  bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8626  (void*)conshdlrdata) );
8627  }
8628  assert(conshdlrdata->bilinhashtable != NULL);
8629 
8630  /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8631  * because zero can not be inserted into hash table
8632  */
8633  SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8634 
8635  /* capture product variables */
8636  SCIP_CALL( SCIPcaptureVar(scip, x) );
8637  SCIP_CALL( SCIPcaptureVar(scip, y) );
8638  }
8639 
8640  return SCIP_OKAY;
8641 }
8642 
8643 /** frees array of bilinear terms and hash table */
8644 static
8646  SCIP* scip, /**< SCIP data structure */
8647  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8648  )
8649 {
8650  int i;
8651  int j;
8652 
8653  assert(conshdlrdata != NULL);
8654 
8655  /* check whether bilinear terms have been stored */
8656  if( conshdlrdata->bilinterms == NULL )
8657  {
8658  assert(conshdlrdata->bilinterms == NULL);
8659  assert(conshdlrdata->nbilinterms == 0);
8660  assert(conshdlrdata->bilintermssize == 0);
8661 
8662  return SCIP_OKAY;
8663  }
8664 
8665  /* release variables */
8666  for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8667  {
8668  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8669  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8670 
8671  for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8672  {
8673  if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8674  {
8675  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8676  }
8677  SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8678  }
8679 
8680  if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8681  {
8682  SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8683  continue;
8684  }
8685 
8686  /* the rest is for simple terms with a single auxvar */
8687 
8688  /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8689  if( conshdlrdata->bilinterms[i].aux.var != NULL )
8690  {
8691  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8692  }
8693  }
8694 
8695  /* free hash table */
8696  if( conshdlrdata->bilinhashtable != NULL )
8697  {
8698  SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8699  }
8700 
8701  /* free bilinterms array; reset counters */
8702  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8703  conshdlrdata->nbilinterms = 0;
8704  conshdlrdata->bilintermssize = 0;
8705 
8706  return SCIP_OKAY;
8707 }
8708 
8709 /*
8710  * vertex polyhedral separation
8711  */
8712 
8713 /** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8714 static
8716  SCIP* scip, /**< SCIP data structure */
8717  int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
8718  SCIP_LPI** lp /**< pointer to store created LP */
8719  )
8720 {
8721  SCIP_Real* obj;
8722  SCIP_Real* lb;
8723  SCIP_Real* ub;
8724  SCIP_Real* val;
8725  int* beg;
8726  int* ind;
8727  unsigned int nnonz;
8728  unsigned int ncols;
8729  unsigned int nrows;
8730  unsigned int i;
8731  unsigned int k;
8732 
8733  assert(scip != NULL);
8734  assert(lp != NULL);
8735  assert(nvars > 0);
8736  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8737 
8738  SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8739 
8740  /* create lpi to store the LP */
8741  SCIP_CALL( SCIPlpiCreate(lp, SCIPgetMessagehdlr(scip), "facet finding LP", SCIP_OBJSEN_MINIMIZE) );
8742 
8743  nrows = (unsigned int)nvars + 1;
8744  ncols = POWEROFTWO((unsigned int)nvars);
8745  nnonz = (ncols * (nrows + 1)) / 2;
8746 
8747  /* allocate necessary memory; set obj, lb, and ub to zero */
8748  SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
8749  SCIP_CALL( SCIPallocClearBufferArray(scip, &lb, ncols) );
8750  SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8751  SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8752  SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8753  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8754 
8755  /* calculate nonzero entries in the LP */
8756  for( i = 0, k = 0; i < ncols; ++i )
8757  {
8758  int row;
8759  unsigned int a;
8760 
8761  /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8762  ub[i] = SCIPlpiInfinity(*lp);
8763 
8764  SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8765  beg[i] = (int)k;
8766  row = 0;
8767 
8768  /* iterate through the bit representation of i */
8769  a = 1;
8770  while( a <= i )
8771  {
8772  if( (a & i) != 0 )
8773  {
8774  val[k] = 1.0;
8775  ind[k] = row;
8776 
8777  SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
8778 
8779  ++k;
8780  }
8781 
8782  a <<= 1;
8783  ++row;
8784  assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8785  assert(POWEROFTWO(row) == a);
8786  }
8787 
8788  /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8789  val[k] = 1.0;
8790  ind[k] = (int)nrows - 1;
8791  ++k;
8792  SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
8793  }
8794  assert(k == nnonz);
8795 
8796  /* load all data into LP interface
8797  * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8798  */
8799  assert(nrows <= ncols);
8801  (int)ncols, obj, lb, ub, NULL,
8802  (int)nrows, lb, lb, NULL,
8803  (int)nnonz, beg, ind, val) );
8804 
8805  /* for the last row, we can set the rhs to 1.0 already */
8806  ind[0] = (int)nrows - 1;
8807  val[0] = 1.0;
8808  SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8809 
8810  /* free allocated memory */
8811  SCIPfreeBufferArray(scip, &ind);
8812  SCIPfreeBufferArray(scip, &val);
8813  SCIPfreeBufferArray(scip, &beg);
8814  SCIPfreeBufferArray(scip, &ub);
8815  SCIPfreeBufferArray(scip, &lb);
8816  SCIPfreeBufferArray(scip, &obj);
8817 
8818  return SCIP_OKAY;
8819 }
8820 
8821 /** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8822  * \max_{v \in V} f(v) - (\alpha v + \beta) \f$ (\f$\max_{v \in V} \alpha v + \beta - f(v) \f$) where \f$ V \f$ is the
8823  * set of vertices of the domain
8824  */
8825 static
8827  SCIP* scip, /**< SCIP data structure */
8828  SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
8829  SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8830  SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
8831  int nallvars, /**< number of all variables */
8832  int nvars, /**< number of unfixed variables */
8833  int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
8834  SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
8835  SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
8836  )
8837 {
8838  SCIP_Real maxerror;
8839  SCIP_Real facetval;
8840  SCIP_Real funval;
8841  SCIP_Real error;
8842  unsigned int i;
8843  unsigned int ncorners;
8844  unsigned int prev;
8845 
8846  assert(scip != NULL);
8847  assert(funvals != NULL);
8848  assert(box != NULL);
8849  assert(nonfixedpos != NULL);
8850  assert(facetcoefs != NULL);
8851 
8852  ncorners = POWEROFTWO(nvars);
8853  maxerror = 0.0;
8854 
8855  /* check the origin (all variables at lower bound) */
8856  facetval = facetconstant;
8857  for( i = 0; i < (unsigned int) nallvars; ++i )
8858  facetval += facetcoefs[i] * box[2*i];
8859 
8860  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8861  funval = funvals[0];
8862  if( overestimate )
8863  error = funval - facetval;
8864  else
8865  error = facetval - funval;
8866 
8867  /* update maximum error */
8868  maxerror = MAX(error, maxerror);
8869 
8870  prev = 0;
8871  for( i = 1; i < ncorners; ++i )
8872  {
8873  unsigned int gray;
8874  unsigned int diff;
8875  unsigned int pos;
8876  int origpos;
8877 
8878  gray = i ^ (i >> 1);
8879  diff = gray ^ prev;
8880 
8881  /* compute position of unique 1 of diff */
8882  pos = 0;
8883  while( (diff >>= 1) != 0 )
8884  ++pos;
8885  assert(pos < (unsigned int)nvars);
8886 
8887  origpos = nonfixedpos[pos];
8888 
8889  if( gray > prev )
8890  facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8891  else
8892  facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8893 
8894  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8895  funval = funvals[gray];
8896  if( overestimate )
8897  error = funval - facetval;
8898  else
8899  error = facetval - funval;
8900 
8901  /* update maximum error */
8902  maxerror = MAX(error, maxerror);
8903 
8904  prev = gray;
8905  }
8906 
8907  SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8908 
8909  return maxerror;
8910 }
8911 
8912 /** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
8913 static
8915  SCIP* scip, /**< SCIP data structure */
8916  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8917  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8918  SCIP_Real* xstar, /**< point to be separated */
8919  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8920  int nallvars, /**< half of the length of box */
8921  int* nonfixedpos, /**< indices of nonfixed variables */
8922  SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
8923  int nvars, /**< number of nonfixed variables */
8924  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
8925  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
8926  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8927  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
8928  )
8929 { /*lint --e{715}*/
8930  SCIP_CONSHDLRDATA* conshdlrdata;
8931  SCIP_LPI* lp;
8932  SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8933  int* inds;
8934  int ncols;
8935  int nrows;
8936  int i;
8937  SCIP_Real facetvalue;
8938  SCIP_Real mindomwidth;
8939  SCIP_RETCODE lpsolveretcode;
8940 
8941  assert(scip != NULL);
8942  assert(conshdlr != NULL);
8943  assert(xstar != NULL);
8944  assert(box != NULL);
8945  assert(nonfixedpos != NULL);
8946  assert(funvals != NULL);
8947  assert(nvars >= 0);
8948  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8949  assert(success != NULL);
8950  assert(facetcoefs != NULL);
8951  assert(facetconstant != NULL);
8952 
8953  *success = FALSE;
8954 
8955  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8956  assert(conshdlrdata != NULL);
8957 
8958  if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8959  {
8960  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8961  }
8962 
8963  /* construct an LP for this size, if not having one already */
8964  if( conshdlrdata->vp_lp[nvars] == NULL )
8965  {
8966  SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8967  }
8968  lp = conshdlrdata->vp_lp[nvars];
8969  assert(lp != NULL);
8970 
8971  /* get number of cols and rows of separation lp */
8972  SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8973  SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8974 
8975  /* number of columns should equal the number of corners = 2^nvars */
8976  assert(ncols == (int)POWEROFTWO(nvars));
8977 
8978  /* allocate necessary memory */
8979  SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8980  SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8981 
8982  /*
8983  * set up the described LP on the transformed space
8984  */
8985 
8986  for( i = 0; i < ncols; ++i )
8987  inds[i] = i;
8988 
8989  /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
8990  mindomwidth = 2*SCIPinfinity(scip);
8991  for( i = 0; i < nrows-1; ++i )
8992  {
8993  SCIP_Real solval;
8994  SCIP_Real lb;
8995  SCIP_Real ub;
8996  int varpos;
8997 
8998  assert(i < nvars);
8999 
9000  varpos = nonfixedpos[i];
9001  lb = box[2 * varpos];
9002  ub = box[2 * varpos + 1];
9003  solval = xstar[varpos];
9004 
9005  if( ub - lb < mindomwidth )
9006  mindomwidth = ub - lb;
9007 
9008  /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9009  if( solval <= lb )
9010  aux[i] = 0.0;
9011  else if( solval >= ub )
9012  aux[i] = 1.0;
9013  else
9014  aux[i] = (solval - lb) / (ub - lb);
9015 
9016  /* perturb point to hopefully obtain a facet of the convex envelope */
9017  if( conshdlrdata->vp_maxperturb > 0.0 )
9018  {
9019  assert(conshdlrdata->vp_randnumgen != NULL);
9020 
9021  if( aux[i] == 1.0 )
9022  aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9023  else if( aux[i] == 0.0 )
9024  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9025  else
9026  {
9027  SCIP_Real perturbation;
9028 
9029  perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9030  perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9031  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9032  }
9033  assert(0.0 < aux[i] && aux[i] < 1.0);
9034  }
9035 
9036  SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9037  }
9038 
9039  /* update LP */
9040  SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9041  SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9043 
9044  /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9045  if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9046  {
9047  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9048  }
9049  /* set an iteration limit so we do not run forever */
9050  SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPITLIM, 100*ncols) );
9051  /* since we work with the dual of the LP, primal feastol determines how much we want the computed facet to be the best possible one */
9053  /* since we work with the dual of the LP, dual feastol determines validity of the facet
9054  * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9055  * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9056  */
9057  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, MIN(SCIPfeastol(scip), MAX(SCIPepsilon(scip), mindomwidth * SCIPfeastol(scip)))) );
9058 
9059 #ifdef SCIP_DEBUG
9061 #endif
9062 
9063  /*
9064  * solve the LP and store the resulting facet for the transformed space
9065  */
9066  if( conshdlrdata->vp_dualsimplex )
9067  {
9068  lpsolveretcode = SCIPlpiSolveDual(lp);
9069  }
9070  else
9071  {
9072  lpsolveretcode = SCIPlpiSolvePrimal(lp);
9073  }
9074  if( lpsolveretcode == SCIP_LPERROR )
9075  {
9076  SCIPdebugMsg(scip, "LP error, aborting.\n");
9077  goto CLEANUP;
9078  }
9079  SCIP_CALL( lpsolveretcode );
9080 
9081  /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9082  if( !SCIPlpiIsDualFeasible(lp) )
9083  {
9084  SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9085  goto CLEANUP;
9086  }
9087 
9088  /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9089  * columns than needed, in particular, \bar \beta is the last dual multiplier
9090  */
9091  SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9092 
9093  for( i = 0; i < nvars; ++i )
9094  facetcoefs[nonfixedpos[i]] = aux[i];
9095  /* last dual multiplier is the constant */
9096  *facetconstant = aux[nrows - 1];
9097 
9098 #ifdef SCIP_DEBUG
9099  SCIPdebugMsg(scip, "facet for the transformed problem: ");
9100  for( i = 0; i < nallvars; ++i )
9101  {
9102  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9103  }
9104  SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9105 #endif
9106 
9107  /*
9108  * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9109  */
9110 
9111  SCIPdebugMsg(scip, "facet in orig. space: ");
9112 
9113  facetvalue = 0.0;
9114  for( i = 0; i < nvars; ++i )
9115  {
9116  SCIP_Real lb;
9117  SCIP_Real ub;
9118  int varpos;
9119 
9120  varpos = nonfixedpos[i];
9121  lb = box[2 * varpos];
9122  ub = box[2 * varpos + 1];
9123  assert(!SCIPisEQ(scip, lb, ub));
9124 
9125  /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9126  facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9127 
9128  /* beta = beta_bar - sum_i alpha_i * lb_i */
9129  *facetconstant -= facetcoefs[varpos] * lb;
9130 
9131  /* evaluate */
9132  facetvalue += facetcoefs[varpos] * xstar[varpos];
9133 
9134  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9135  }
9136  SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9137 
9138  /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9139  facetvalue += *facetconstant;
9140 
9141  SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9142 
9143  /* if overestimate, then we want facetvalue < targetvalue
9144  * if underestimate, then we want facetvalue > targetvalue
9145  * if none holds, give up
9146  * so maybe here we should check against the minimal violation
9147  */
9148  if( overestimate == (facetvalue > targetvalue) )
9149  {
9150  SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9151  goto CLEANUP;
9152  }
9153 
9154  /* if we made it until here, then we have a nice facet */
9155  *success = TRUE;
9156 
9157 CLEANUP:
9158  /* free allocated memory */
9159  SCIPfreeBufferArray(scip, &inds);
9160  SCIPfreeBufferArray(scip, &aux);
9161 
9162  return SCIP_OKAY;
9163 }
9164 
9165 /** computes a facet of the convex or concave envelope of a univariant vertex polyhedral function
9166  *
9167  * In other words, compute the line that passes through two given points.
9168  */
9169 static
9171  SCIP* scip, /**< SCIP data structure */
9172  SCIP_Real left, /**< left coordinate */
9173  SCIP_Real right, /**< right coordinate */
9174  SCIP_Real funleft, /**< value of function in left coordinate */
9175  SCIP_Real funright, /**< value of function in right coordinate */
9176  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9177  SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9178  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9179  )
9180 {
9181  assert(scip != NULL);
9182  assert(SCIPisLE(scip, left, right));
9183  assert(!SCIPisInfinity(scip, -left));
9184  assert(!SCIPisInfinity(scip, right));
9185  assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9186  assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9187  assert(success != NULL);
9188  assert(facetcoef != NULL);
9189  assert(facetconstant != NULL);
9190 
9191  *facetcoef = (funright - funleft) / (right - left);
9192  *facetconstant = funleft - *facetcoef * left;
9193 
9194  *success = TRUE;
9195 
9196  return SCIP_OKAY;
9197 }
9198 
9199 /** given three points, constructs coefficient of equation for hyperplane generated by these three points
9200  *
9201  * Three points a, b, and c are given.
9202  * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9203  * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9204  */
9205 static
9207  SCIP* scip, /**< SCIP data structure */
9208  SCIP_Real a1, /**< first coordinate of a */
9209  SCIP_Real a2, /**< second coordinate of a */
9210  SCIP_Real a3, /**< third coordinate of a */
9211  SCIP_Real b1, /**< first coordinate of b */
9212  SCIP_Real b2, /**< second coordinate of b */
9213  SCIP_Real b3, /**< third coordinate of b */
9214  SCIP_Real c1, /**< first coordinate of c */
9215  SCIP_Real c2, /**< second coordinate of c */
9216  SCIP_Real c3, /**< third coordinate of c */
9217  SCIP_Real* alpha, /**< coefficient of first coordinate */
9218  SCIP_Real* beta, /**< coefficient of second coordinate */
9219  SCIP_Real* gamma_, /**< coefficient of third coordinate */
9220  SCIP_Real* delta /**< constant right-hand side */
9221  )
9222 {
9223  assert(scip != NULL);
9224  assert(alpha != NULL);
9225  assert(beta != NULL);
9226  assert(gamma_ != NULL);
9227  assert(delta != NULL);
9228 
9229  *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9230  *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9231  *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9232  *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9233 
9234  /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9235 
9236  if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9237  SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9238  SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9239  {
9240  SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9241  *delta = 0.0;
9242  *alpha = 0.0;
9243  *beta = 0.0;
9244  *gamma_ = 0.0;
9245  return SCIP_OKAY;
9246  }
9247 
9248  /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9249  if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9250  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9251  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9252  {
9253  SCIP_Real m[9];
9254  SCIP_Real rhs[3];
9255  SCIP_Real x[3];
9256  SCIP_Bool success;
9257 
9258  /*
9259  SCIPdebugMsg(scip, "a = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", a1, a2, a3, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3, SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3));
9260  SCIPdebugMsg(scip, "b = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", b1, b2, b3, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3, SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3));
9261  SCIPdebugMsg(scip, "c = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", c1, c2, c3, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3, SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3));
9262  */
9263 
9264  /* initialize matrix column-wise */
9265  m[0] = a1;
9266  m[1] = b1;
9267  m[2] = c1;
9268  m[3] = a2;
9269  m[4] = b2;
9270  m[5] = c2;
9271  m[6] = a3;
9272  m[7] = b3;
9273  m[8] = c3;
9274 
9275  rhs[0] = 1.0;
9276  rhs[1] = 1.0;
9277  rhs[2] = 1.0;
9278 
9279  SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9280 
9281  /* solve the linear problem */
9282  SCIP_CALL( SCIPsolveLinearEquationsIpopt(3, m, rhs, x, &success) );
9283 
9284  *delta = rhs[0];
9285  *alpha = x[0];
9286  *beta = x[1];
9287  *gamma_ = x[2];
9288 
9289  /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9290  * not add a cut to SCIP and that all assertions are trivially fulfilled
9291  */
9292  if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9293  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9294  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9295  {
9296  SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9297  *delta = 0.0;
9298  *alpha = 0.0;
9299  *beta = 0.0;
9300  *gamma_ = 0.0;
9301  }
9302  }
9303 
9304  if( *gamma_ < 0.0 )
9305  {
9306  *alpha = -*alpha;
9307  *beta = -*beta;
9308  *gamma_ = -*gamma_;
9309  *delta = -*delta;
9310  }
9311 
9312  return SCIP_OKAY;
9313 }
9314 
9315 /** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9316 static
9318  SCIP* scip, /**< SCIP data structure */
9319  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9320  SCIP_Real p1[2], /**< first vertex of box */
9321  SCIP_Real p2[2], /**< second vertex of box */
9322  SCIP_Real p3[2], /**< third vertex of box */
9323  SCIP_Real p4[2], /**< forth vertex of box */
9324  SCIP_Real p1val, /**< value in p1 */
9325  SCIP_Real p2val, /**< value in p2 */
9326  SCIP_Real p3val, /**< value in p3 */
9327  SCIP_Real p4val, /**< value in p4 */
9328  SCIP_Real xstar[2], /**< point to be separated */
9329  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9330  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9331  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9332  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9333  )
9334 {
9335  SCIP_Real alpha, beta, gamma_, delta;
9336  SCIP_Real xstarval, candxstarval = 0.0;
9337  int leaveout;
9338 
9339  assert(scip != NULL);
9340  assert(success != NULL);
9341  assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9342  assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9343  assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9344  assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9345  assert(facetcoefs != NULL);
9346  assert(facetconstant != NULL);
9347 
9348  *success = FALSE;
9349 
9350  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9351  if( !overestimate )
9352  {
9353  p1val = -p1val;
9354  p2val = -p2val;
9355  p3val = -p3val;
9356  p4val = -p4val;
9357  targetvalue = -targetvalue;
9358  }
9359 
9360  SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9361  SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9362  SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9363  SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9364 
9365  /* Compute coefficients alpha, beta, gamma (>0), delta such that
9366  * alpha*x + beta*y + gamma*z = delta
9367  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9368  * the fourth corner point lies below this hyperplane.
9369  * Since we assume that f is vertex-polyhedral, we then know that all points (x,y,f(x,y)) are below this hyperplane, i.e.,
9370  * alpha*x + beta*y - delta <= -gamma * f(x,y),
9371  * or, equivalently,
9372  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9373  */
9374  for( leaveout = 1; leaveout <= 4; ++leaveout )
9375  {
9376  switch( leaveout)
9377  {
9378  case 1 :
9379  /* get hyperplane through p2, p3, p4 */
9380  SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9381  &alpha, &beta, &gamma_, &delta) );
9382  /* if not underestimating in p1, then go to next candidate */
9383  if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9384  continue;
9385  break;
9386 
9387  case 2 :
9388  /* get hyperplane through p1, p3, p4 */
9389  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9390  &alpha, &beta, &gamma_, &delta) );
9391  /* if not underestimating in p2, then go to next candidate */
9392  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9393  continue;
9394  break;
9395 
9396  case 3 :
9397  /* get hyperplane through p1, p2, p4 */
9398  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9399  &alpha, &beta, &gamma_, &delta) );
9400  /* if not underestimating in p3, then go to next candidate */
9401  if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9402  continue;
9403  break;
9404 
9405  case 4 :
9406  /* get hyperplane through p1, p2, p3 */
9407  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9408  &alpha, &beta, &gamma_, &delta) );
9409  /* if not underestimating in p4, then stop */
9410  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9411  continue;
9412  break;
9413 
9414  default: /* only for lint */
9415  alpha = SCIP_INVALID;
9416  beta = SCIP_INVALID;
9417  gamma_ = SCIP_INVALID;
9418  delta = SCIP_INVALID;
9419  break;
9420  }
9421 
9422  /* check if bad luck: should not happen if numerics are fine */
9423  if( SCIPisZero(scip, gamma_) )
9424  continue;
9425  assert(!SCIPisNegative(scip, gamma_));
9426 
9427  /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9428  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9429  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9430  continue;
9431 
9432  SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9433 
9434  /* value of hyperplane candidate in xstar */
9435  xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9436 
9437  /* if reaching target and first or better than previous candidate, then update */
9438  if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9439  {
9440  /* flip hyperplane */
9441  if( !overestimate )
9442  gamma_ = -gamma_;
9443 
9444  facetcoefs[0] = -alpha/gamma_;
9445  facetcoefs[1] = -beta/gamma_;
9446  *facetconstant = delta/gamma_;
9447 
9448  *success = TRUE;
9449  candxstarval = xstarval;
9450  }
9451  }
9452 
9453  return SCIP_OKAY;
9454 }
9455 
9456 /*
9457  * Callback methods of constraint handler
9458  */
9459 
9460 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
9461 static
9462 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
9463 { /*lint --e{715}*/
9464  SCIP_CONSHDLR* targetconshdlr;
9465  SCIP_CONSHDLRDATA* sourceconshdlrdata;
9466  int i;
9467 
9468  assert(scip != NULL);
9469  assert(conshdlr != NULL);
9470  assert(valid != NULL);
9471  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
9472 
9473  /* create basic data of constraint handler and include it to scip */
9475 
9476  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9477  assert(targetconshdlr != NULL);
9478  assert(targetconshdlr != conshdlr);
9479 
9480  sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
9481  assert(sourceconshdlrdata != NULL);
9482 
9483  /* copy nonlinear handlers */
9484  for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
9485  {
9486  SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
9487  }
9488 
9489  *valid = TRUE;
9490 
9491  return SCIP_OKAY;
9492 }
9493 
9494 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9495 static
9496 SCIP_DECL_CONSFREE(consFreeNonlinear)
9497 { /*lint --e{715}*/
9498  SCIP_CONSHDLRDATA* conshdlrdata;
9499  int i;
9500 
9501  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9502  assert(conshdlrdata != NULL);
9503 
9504  /* free nonlinear handlers */
9505  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9506  {
9507  SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
9508  assert(conshdlrdata->nlhdlrs[i] == NULL);
9509  }
9510  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
9511  conshdlrdata->nlhdlrssize = 0;
9512 
9513  /* free upgrade functions */
9514  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
9515  {
9516  assert(conshdlrdata->consupgrades[i] != NULL);
9517  SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
9518  }
9519  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
9520 
9521  SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
9522 
9523  SCIPqueueFree(&conshdlrdata->reversepropqueue);
9524 
9525  if( conshdlrdata->vp_randnumgen != NULL )
9526  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9527 
9528  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9529  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9530  {
9531  if( conshdlrdata->vp_lp[i] != NULL )
9532  {
9533  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9534  }
9535  }
9536 
9537  assert(conshdlrdata->branchrandnumgen == NULL);
9538 
9539  assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
9540  SCIPhashmapFree(&conshdlrdata->var2expr);
9541 
9542  SCIPfreeMemory(scip, &conshdlrdata);
9543  SCIPconshdlrSetData(conshdlr, NULL);
9544 
9545  return SCIP_OKAY;
9546 }
9547 
9548 
9549 /** initialization method of constraint handler (called after problem was transformed) */
9550 static
9551 SCIP_DECL_CONSINIT(consInitNonlinear)
9552 { /*lint --e{715}*/
9553  SCIP_CONSHDLRDATA* conshdlrdata;
9554  int i;
9555 
9556  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9557  assert(conshdlrdata != NULL);
9558 
9559  /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
9560  conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
9561  /* set to 1 so it is larger than initial value of lastenforound in exprs */
9562  conshdlrdata->enforound = 1;
9563  /* reset numbering for auxiliary variables */
9564  conshdlrdata->auxvarid = 0;
9565 
9566  for( i = 0; i < nconss; ++i )
9567  {
9568  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
9569  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
9570  }
9571 
9572  /* sort nonlinear handlers by detection priority, in decreasing order */
9573  if( conshdlrdata->nnlhdlrs > 1 )
9574  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
9575 
9576  /* get heuristics for later use */
9577  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9578  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9579 
9580  /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
9581  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9582  {
9583  SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
9584  }
9585 
9586  /* reset statistics in constraint handler */
9587  conshdlrdata->nweaksepa = 0;
9588  conshdlrdata->ntightenlp = 0;
9589  conshdlrdata->ndesperatebranch = 0;
9590  conshdlrdata->ndesperatecutoff = 0;
9591  conshdlrdata->ndesperatetightenlp = 0;
9592  conshdlrdata->nforcelp = 0;
9593  SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
9594  conshdlrdata->ncanonicalizecalls = 0;
9595 
9596 #ifdef ENFOLOGFILE
9597  ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
9598 #endif
9599 
9600  return SCIP_OKAY;
9601 }
9602 
9603 
9604 /** deinitialization method of constraint handler (called before transformed problem is freed) */
9605 static
9606 SCIP_DECL_CONSEXIT(consExitNonlinear)
9607 { /*lint --e{715}*/
9608  SCIP_CONSHDLRDATA* conshdlrdata;
9609  SCIP_CONS** consssorted;
9610  int i;
9611 
9612  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9613  assert(conshdlrdata != NULL);
9614 
9615  if( nconss > 0 )
9616  {
9617  /* for better performance of dropVarEvents, we sort by index, descending */
9618  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
9619  SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
9620 
9621  for( i = 0; i < nconss; ++i )
9622  {
9623  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
9624  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
9625  }
9626 
9627  SCIPfreeBufferArray(scip, &consssorted);
9628  }
9629 
9630  conshdlrdata->subnlpheur = NULL;
9631  conshdlrdata->trysolheur = NULL;
9632 
9633  if( conshdlrdata->vp_randnumgen != NULL )
9634  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9635 
9636  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9637  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9638  {
9639  if( conshdlrdata->vp_lp[i] != NULL )
9640  {
9641  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9642  }
9643  }
9644 
9645  if( conshdlrdata->branchrandnumgen != NULL )
9646  SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
9647 
9648  /* deinitialize nonlinear handlers */
9649  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9650  {
9651  SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
9652  }
9653 
9654  ENFOLOG(
9655  if( enfologfile != NULL )
9656  {
9657  fclose(enfologfile);
9658  enfologfile = NULL;
9659  })
9660 
9661  return SCIP_OKAY;
9662 }
9663 
9664 
9665 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
9666 #ifdef SCIP_DISABLED_CODE
9667 static
9669 { /*lint --e{715}*/
9670  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
9671  SCIPABORT(); /*lint --e{527}*/
9672 
9673  return SCIP_OKAY;
9674 }
9675 #else
9676 #define consInitpreNonlinear NULL
9677 #endif
9678 
9679 
9680 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9681 static
9682 SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
9683 { /*lint --e{715}*/
9684  SCIP_Bool infeasible;
9685 
9686  if( nconss == 0 )
9687  return SCIP_OKAY;
9688 
9689  /* skip some extra work if already known to be infeasible */
9690  if( SCIPgetStatus(scip) == SCIP_STATUS_INFEASIBLE )
9691  return SCIP_OKAY;
9692 
9693  /* simplify constraints and replace common subexpressions */
9694  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
9695 
9696  /* currently SCIP does not offer to communicate this,
9697  * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
9698  * or if a constraint expression became constant
9699  */
9700  assert(!infeasible);
9701 
9702  /* tell SCIP that we have something nonlinear */
9703  SCIPenableNLP(scip);
9704 
9705  return SCIP_OKAY;
9706 }
9707 
9708 
9709 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
9710 static
9711 SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
9712 { /*lint --e{715}*/
9713  SCIP_CONSHDLRDATA* conshdlrdata;
9714  int i;
9715 
9716  /* skip remaining initializations if we have solved already
9717  * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
9718  * assumes nonempty activities in expressions
9719  */
9720  switch( SCIPgetStatus(scip) )
9721  {
9722  case SCIP_STATUS_OPTIMAL:
9724  case SCIP_STATUS_UNBOUNDED:
9725  case SCIP_STATUS_INFORUNBD:
9726  return SCIP_OKAY;
9727  default: ;
9728  } /*lint !e788 */
9729 
9730  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9731  assert(conshdlrdata != NULL);
9732 
9733  /* reset one of the number of detections counter to count only current round */
9734  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9735  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
9736 
9737  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
9738 
9739  /* catch new solution event */
9740  if( nconss != 0 && conshdlrdata->linearizeheursol != 'o' )
9741  {
9742  SCIP_EVENTHDLR* eventhdlr;
9743 
9744  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9745  assert(eventhdlr != NULL);
9746 
9747  SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
9748  eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9749  }
9750 
9751  /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
9752  if( conshdlrdata->branchpscostweight > 0.0 )
9753  {
9754  SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
9755  if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
9756  {
9757  SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
9758  SCIPABORT();
9759  return SCIP_INVALIDDATA;
9760  }
9761  }
9762 
9763  return SCIP_OKAY;
9764 }
9765 
9766 
9767 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9768 static
9769 SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
9770 { /*lint --e{715}*/
9771  SCIP_CONSHDLRDATA* conshdlrdata;
9772 
9773  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
9774 
9775  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9776  assert(conshdlrdata != NULL);
9777 
9778  /* free hash table for bilinear terms */
9779  SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
9780 
9781  /* reset flag to allow another call of presolSingleLockedVars() after a restart */
9782  conshdlrdata->checkedvarlocks = FALSE;
9783 
9784  /* drop catching new solution event, if catched before */
9785  if( conshdlrdata->newsoleventfilterpos >= 0 )
9786  {
9787  SCIP_EVENTHDLR* eventhdlr;
9788 
9789  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9790  assert(eventhdlr != NULL);
9791 
9792  SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9793  conshdlrdata->newsoleventfilterpos = -1;
9794  }
9795 
9796  return SCIP_OKAY;
9797 }
9798 
9799 
9800 /** frees specific constraint data */
9801 static
9802 SCIP_DECL_CONSDELETE(consDeleteNonlinear)
9803 { /*lint --e{715}*/
9804  assert(consdata != NULL);
9805  assert(*consdata != NULL);
9806  assert((*consdata)->expr != NULL);
9807 
9808  /* constraint locks should have been removed */
9809  assert((*consdata)->nlockspos == 0);
9810  assert((*consdata)->nlocksneg == 0);
9811 
9812  /* free variable expressions */
9813  SCIP_CALL( freeVarExprs(scip, *consdata) );
9814 
9815  SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
9816 
9817  /* free nonlinear row representation */
9818  if( (*consdata)->nlrow != NULL )
9819  {
9820  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
9821  }
9822 
9823  SCIPfreeBlockMemory(scip, consdata);
9824 
9825  return SCIP_OKAY;
9826 }
9827 
9828 
9829 /** transforms constraint data into data belonging to the transformed problem */
9830 static
9831 SCIP_DECL_CONSTRANS(consTransNonlinear)
9832 { /*lint --e{715}*/
9833  SCIP_EXPR* targetexpr;
9834  SCIP_CONSDATA* sourcedata;
9835 
9836  sourcedata = SCIPconsGetData(sourcecons);
9837  assert(sourcedata != NULL);
9838 
9839  /* get a copy of sourceexpr with transformed vars */
9840  SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
9841  assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
9842 
9843  /* create transformed cons (only captures targetexpr, no need to copy again) */
9844  SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
9845  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
9846  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
9847  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
9848  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
9849  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
9850 
9851  /* release target expr */
9852  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
9853 
9854  return SCIP_OKAY;
9855 }
9856 
9857 
9858 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9859 static
9860 SCIP_DECL_CONSINITLP(consInitlpNonlinear)
9861 { /*lint --e{715}*/
9862  /* create auxiliary variables and call separation initialization callbacks of the expression handlers
9863  * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
9864  * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
9865  * for now, there is an assert in detectNlhdlrs to require initial if separated
9866  */
9867  SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
9868 
9869  /* collect all bilinear terms for which an auxvar is present
9870  * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
9871  * addition (and removal?) of constraints during solve
9872  * this is typically the majority of constraints, but the method should be made more flexible
9873  */
9874  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
9875 
9876  return SCIP_OKAY;
9877 }
9878 
9879 
9880 /** separation method of constraint handler for LP solutions */
9881 static
9882 SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
9883 { /*lint --e{715}*/
9884  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
9885 
9886  return SCIP_OKAY;
9887 }
9888 
9889 
9890 /** separation method of constraint handler for arbitrary primal solutions */
9891 static
9892 SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
9893 { /*lint --e{715}*/
9894  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
9895 
9896  return SCIP_OKAY;
9897 }
9898 
9899 
9900 /** constraint enforcing method of constraint handler for LP solutions */
9901 static
9902 SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
9903 { /*lint --e{715}*/
9904  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
9905 
9906  return SCIP_OKAY;
9907 }
9908 
9909 
9910 /** constraint enforcing method of constraint handler for relaxation solutions */
9911 static
9912 SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
9913 { /*lint --e{715}*/
9914  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
9915 
9916  return SCIP_OKAY;
9917 }
9918 
9919 
9920 /** constraint enforcing method of constraint handler for pseudo solutions */
9921 static
9922 SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
9923 { /*lint --e{715}*/
9924  SCIP_RESULT propresult;
9925  SCIP_Longint soltag;
9926  int nchgbds;
9927  int nnotify;
9928  int c;
9929 
9930  soltag = SCIPgetExprNewSoltag(scip);
9931 
9932  *result = SCIP_FEASIBLE;
9933  for( c = 0; c < nconss; ++c )
9934  {
9935  SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
9936 
9937  if( isConsViolated(scip, conss[c]) )
9938  *result = SCIP_INFEASIBLE;
9939  }
9940 
9941  if( *result == SCIP_FEASIBLE )
9942  return SCIP_OKAY;
9943 
9944  /* try to propagate
9945  * TODO obey propinenfo parameter, but we need something to recognize cutoff
9946  */
9947  nchgbds = 0;
9948  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
9949 
9950  if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
9951  {
9952  *result = propresult;
9953  return SCIP_OKAY;
9954  }
9955 
9956  /* register all unfixed variables in all violated constraints as branching candidates */
9957  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
9958  if( nnotify > 0 )
9959  {
9960  SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
9961 
9962  return SCIP_OKAY;
9963  }
9964 
9965  SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
9966  *result = SCIP_SOLVELP;
9967  ++SCIPconshdlrGetData(conshdlr)->nforcelp;
9968 
9969  return SCIP_OKAY;
9970 }
9971 
9972 
9973 /** feasibility check method of constraint handler for integral solutions */
9974 static
9975 SCIP_DECL_CONSCHECK(consCheckNonlinear)
9976 { /*lint --e{715}*/
9977  SCIP_CONSHDLRDATA* conshdlrdata;
9978  SCIP_CONSDATA* consdata;
9979  SCIP_Real maxviol;
9980  SCIP_Bool maypropfeasible;
9981  SCIP_Longint soltag;
9982  int c;
9983 
9984  assert(scip != NULL);
9985  assert(conshdlr != NULL);
9986  assert(conss != NULL || nconss == 0);
9987  assert(result != NULL);
9988 
9989  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9990  assert(conshdlrdata != NULL);
9991 
9992  *result = SCIP_FEASIBLE;
9993  soltag = SCIPgetExprNewSoltag(scip);
9994  maxviol = 0.0;
9995  maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
9996  && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING;
9997 
9998  /* check nonlinear constraints for feasibility */
9999  for( c = 0; c < nconss; ++c )
10000  {
10001  assert(conss != NULL && conss[c] != NULL);
10002  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
10003 
10004  if( isConsViolated(scip, conss[c]) )
10005  {
10006  *result = SCIP_INFEASIBLE;
10007  maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
10008 
10009  consdata = SCIPconsGetData(conss[c]);
10010  assert(consdata != NULL);
10011 
10012  /* print reason for infeasibility */
10013  if( printreason )
10014  {
10015  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
10016  SCIPinfoMessage(scip, NULL, ";\n");
10017 
10018  if( consdata->lhsviol > SCIPfeastol(scip) )
10019  {
10020  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
10021  }
10022  if( consdata->rhsviol > SCIPfeastol(scip) )
10023  {
10024  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
10025  }
10026  }
10027  else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
10028  {
10029  /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
10030  return SCIP_OKAY;
10031  }
10032 
10033  /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
10034  if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
10035  maypropfeasible = FALSE;
10036 
10037  if( maypropfeasible )
10038  {
10039  if( consdata->lhsviol > SCIPfeastol(scip) )
10040  {
10041  /* check if there is a variable which may help to get the left hand side satisfied
10042  * if there is no such variable, then we cannot get feasible
10043  */
10044  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
10045  !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
10046  maypropfeasible = FALSE;
10047  }
10048  else
10049  {
10050  assert(consdata->rhsviol > SCIPfeastol(scip));
10051  /* check if there is a variable which may help to get the right hand side satisfied
10052  * if there is no such variable, then we cannot get feasible
10053  */
10054  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
10055  !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
10056  maypropfeasible = FALSE;
10057  }
10058  }
10059  }
10060  }
10061 
10062  if( *result == SCIP_INFEASIBLE && maypropfeasible )
10063  {
10064  SCIP_Bool success;
10065 
10066  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
10067 
10068  /* do not pass solution to NLP heuristic if we made it feasible this way */
10069  if( success )
10070  return SCIP_OKAY;
10071  }
10072 
10073  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
10074  {
10075  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
10076  }
10077 
10078  return SCIP_OKAY;
10079 }
10080 
10081 
10082 /** domain propagation method of constraint handler */
10083 static
10084 SCIP_DECL_CONSPROP(consPropNonlinear)
10085 { /*lint --e{715}*/
10086  int nchgbds = 0;
10087 
10088  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
10089  assert(nchgbds >= 0);
10090 
10091  /* TODO would it make sense to check for redundant constraints? */
10092 
10093  return SCIP_OKAY;
10094 }
10095 
10096 
10097 /** presolving method of constraint handler */
10098 static
10099 SCIP_DECL_CONSPRESOL(consPresolNonlinear)
10100 { /*lint --e{715}*/
10101  SCIP_CONSHDLRDATA* conshdlrdata;
10102  SCIP_Bool infeasible;
10103  int c;
10104 
10105  *result = SCIP_DIDNOTFIND;
10106 
10107  if( nconss == 0 )
10108  {
10109  *result = SCIP_DIDNOTRUN;
10110  return SCIP_OKAY;
10111  }
10112 
10113  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10114  assert(conshdlrdata != NULL);
10115 
10116  /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
10117  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
10118  if( infeasible )
10119  {
10120  *result = SCIP_CUTOFF;
10121  return SCIP_OKAY;
10122  }
10123 
10124  /* merge constraints with the same root expression */
10125  if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
10126  {
10127  SCIP_Bool success;
10128 
10129  SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
10130  if( success )
10131  *result = SCIP_SUCCESS;
10132  }
10133 
10134  /* propagate constraints */
10135  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
10136  if( *result == SCIP_CUTOFF )
10137  return SCIP_OKAY;
10138 
10139  /* propagate function domains (TODO integrate with simplify?) */
10140  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
10141  {
10142  SCIP_RESULT localresult;
10143  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
10144  if( localresult == SCIP_CUTOFF )
10145  {
10146  *result = SCIP_CUTOFF;
10147  return SCIP_OKAY;
10148  }
10149  if( localresult == SCIP_REDUCEDDOM )
10150  *result = SCIP_REDUCEDDOM;
10151  }
10152 
10153  /* check for redundant constraints, remove constraints that are a value expression */
10154  SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
10155  if( infeasible )
10156  {
10157  *result = SCIP_CUTOFF;
10158  return SCIP_OKAY;
10159  }
10160 
10161  /* try to upgrade constraints */
10162  for( c = 0; c < nconss; ++c )
10163  {
10164  SCIP_Bool upgraded;
10165 
10166  /* skip inactive and deleted constraints */
10167  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
10168  continue;
10169 
10170  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10171  }
10172 
10173  /* try to change continuous variables that appear linearly to be implicit integer */
10174  if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
10175  {
10176  SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
10177 
10178  if( infeasible )
10179  {
10180  SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
10181  *result = SCIP_CUTOFF;
10182  return SCIP_OKAY;
10183  }
10184  }
10185 
10186  /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
10187  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) && SCIPisPresolveFinished(scip)
10188  && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
10189  {
10190  /* run this presolving technique only once because we don't want to generate identical bound disjunction
10191  * constraints multiple times
10192  */
10193  conshdlrdata->checkedvarlocks = TRUE;
10194 
10195  for( c = 0; c < nconss; ++c )
10196  {
10197  int tmpnchgvartypes = 0;
10198  int tmpnaddconss = 0;
10199 
10200  SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
10201  SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
10202  SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
10203 
10204  if( infeasible )
10205  {
10206  SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
10207  *result = SCIP_CUTOFF;
10208  return SCIP_OKAY;
10209  }
10210 
10211  (*nchgvartypes) += tmpnchgvartypes;
10212  (*naddconss) += tmpnaddconss;
10213  }
10214  }
10215 
10216  if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
10217  *result = SCIP_SUCCESS;
10218  else
10219  *result = SCIP_DIDNOTFIND;
10220 
10221  return SCIP_OKAY;
10222 }
10223 
10224 
10225 /** propagation conflict resolving method of constraint handler */
10226 #ifdef SCIP_DISABLED_CODE
10227 static
10229 { /*lint --e{715}*/
10230  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10231  SCIPABORT(); /*lint --e{527}*/
10232 
10233  return SCIP_OKAY;
10234 }
10235 #else
10236 #define consRespropNonlinear NULL
10237 #endif
10238 
10239 
10240 /** variable rounding lock method of constraint handler */
10241 static
10242 SCIP_DECL_CONSLOCK(consLockNonlinear)
10243 { /*lint --e{715}*/
10244  SCIP_CONSDATA* consdata;
10245  SCIP_EXPR_OWNERDATA* ownerdata;
10246  SCIP_Bool reinitsolve = FALSE;
10247 
10248  assert(conshdlr != NULL);
10249  assert(cons != NULL);
10250 
10251  consdata = SCIPconsGetData(cons);
10252  assert(consdata != NULL);
10253  assert(consdata->expr != NULL);
10254 
10255  ownerdata = SCIPexprGetOwnerData(consdata->expr);
10256 
10257  /* check whether we need to initSolve again because
10258  * - we have enfo initialized (nenfos >= 0)
10259  * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
10260  */
10261  if( ownerdata->nenfos >= 0 )
10262  {
10263  if( (consdata->nlockspos == 0) != (nlockspos == 0) )
10264  reinitsolve = TRUE;
10265  if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
10266  reinitsolve = TRUE;
10267  }
10268 
10269  if( reinitsolve )
10270  {
10271  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10272  }
10273 
10274  /* add locks */
10275  SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
10276 
10277  if( reinitsolve )
10278  {
10279  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10280  }
10281 
10282  return SCIP_OKAY;
10283 }
10284 
10285 
10286 /** constraint activation notification method of constraint handler */
10287 static
10288 SCIP_DECL_CONSACTIVE(consActiveNonlinear)
10289 { /*lint --e{715}*/
10290  SCIP_CONSDATA* consdata;
10291  SCIP_Bool infeasible = FALSE;
10292 
10293  consdata = SCIPconsGetData(cons);
10294  assert(consdata != NULL);
10295 
10296  /* simplify root expression if the constraint has been added after presolving */
10298  {
10299  SCIP_Bool replacedroot;
10300 
10301  if( !consdata->issimplified )
10302  {
10303  SCIP_EXPR* simplified;
10304  SCIP_Bool changed;
10305 
10306  /* simplify constraint */
10307  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
10308  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
10309  assert(simplified != NULL);
10310  consdata->expr = simplified;
10311  consdata->issimplified = TRUE;
10312  }
10313 
10314  /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
10315  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
10316  assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
10317 
10318  /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
10319  {
10320  SCIP_CONSHDLRDATA* conshdlrdata;
10321  SCIP_EXPRITER* it;
10322  SCIP_EXPR* expr;
10323 
10324  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10325  assert(conshdlrdata != NULL);
10326 
10327  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
10328  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
10330  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10331  {
10332  SCIP_EXPR* child;
10333  SCIP_EXPR* hashmapexpr;
10334 
10335  child = SCIPexpriterGetChildExprDFS(it);
10336  if( !SCIPisExprVar(scip, child) )
10337  continue;
10338 
10339  /* check which expression is stored in the hashmap for the var of child */
10340  hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
10341  /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
10342  if( hashmapexpr != NULL && hashmapexpr != child )
10343  {
10344  SCIP_CALL( SCIPreplaceExprChild(scip, expr, SCIPexpriterGetChildIdxDFS(it), hashmapexpr) );
10345  }
10346  }
10347  SCIPfreeExpriter(&it);
10348  }
10349  }
10350 
10351  /* store variable expressions */
10352  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10353  {
10354  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10355  }
10356 
10357  /* add manually locks to constraints that are not checked for feasibility */
10358  if( !SCIPconsIsChecked(cons) )
10359  {
10360  assert(consdata->nlockspos == 0);
10361  assert(consdata->nlocksneg == 0);
10362 
10363  SCIP_CALL( addLocks(scip, cons, 1, 0) );
10364  }
10365 
10366  if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
10367  {
10368  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10369  }
10370 
10371  /* TODO deal with infeasibility */
10372  assert(!infeasible);
10373 
10374  return SCIP_OKAY;
10375 }
10376 
10377 
10378 /** constraint deactivation notification method of constraint handler */
10379 static
10380 SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
10381 { /*lint --e{715}*/
10382  SCIP_CONSHDLRDATA* conshdlrdata;
10383 
10384  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10385  assert(conshdlrdata != NULL);
10386 
10387  if( SCIPgetStage(scip) < SCIP_STAGE_EXITSOLVE )
10388  {
10389  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10390  }
10391 
10392  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10393  {
10394  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10395  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(cons)) );
10396  }
10397 
10398  /* remove locks that have been added in consActiveExpr() */
10399  if( !SCIPconsIsChecked(cons) )
10400  {
10401  SCIP_CALL( addLocks(scip, cons, -1, 0) );
10402 
10403  assert(SCIPconsGetData(cons)->nlockspos == 0);
10404  assert(SCIPconsGetData(cons)->nlocksneg == 0);
10405  }
10406 
10407  return SCIP_OKAY;
10408 }
10409 
10410 
10411 /** constraint enabling notification method of constraint handler */
10412 static
10413 SCIP_DECL_CONSENABLE(consEnableNonlinear)
10414 { /*lint --e{715}*/
10415  SCIP_CONSHDLRDATA* conshdlrdata;
10416 
10417  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10418  assert(conshdlrdata != NULL);
10419 
10420  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10421  {
10422  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10423  }
10424 
10425  return SCIP_OKAY;
10426 }
10427 
10428 
10429 /** constraint disabling notification method of constraint handler */
10430 static
10431 SCIP_DECL_CONSDISABLE(consDisableNonlinear)
10432 { /*lint --e{715}*/
10433  SCIP_CONSHDLRDATA* conshdlrdata;
10434 
10435  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10436  assert(conshdlrdata != NULL);
10437 
10438  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10439  {
10440  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10441  }
10442 
10443  return SCIP_OKAY;
10444 }
10445 
10446 /** variable deletion of constraint handler */
10447 #ifdef SCIP_DISABLED_CODE
10448 static
10450 { /*lint --e{715}*/
10451  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10452  SCIPABORT(); /*lint --e{527}*/
10453 
10454  return SCIP_OKAY;
10455 }
10456 #else
10457 #define consDelvarsNonlinear NULL
10458 #endif
10459 
10460 
10461 /** constraint display method of constraint handler */
10462 static
10463 SCIP_DECL_CONSPRINT(consPrintNonlinear)
10464 { /*lint --e{715}*/
10465  SCIP_CONSDATA* consdata;
10466 
10467  consdata = SCIPconsGetData(cons);
10468  assert(consdata != NULL);
10469  assert(consdata->expr != NULL);
10470 
10471  /* print left hand side for ranged constraints */
10472  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10473  {
10474  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10475  }
10476 
10477  /* print expression */
10478  SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
10479 
10480  /* print right hand side */
10481  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10482  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
10483  else if( !SCIPisInfinity(scip, consdata->rhs) )
10484  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
10485  else if( !SCIPisInfinity(scip, -consdata->lhs) )
10486  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
10487  else
10488  SCIPinfoMessage(scip, file, " [free]");
10489 
10490  return SCIP_OKAY;
10491 }
10492 
10493 
10494 /** constraint copying method of constraint handler */
10495 static
10496 SCIP_DECL_CONSCOPY(consCopyNonlinear)
10497 { /*lint --e{715}*/
10498  SCIP_CONSHDLR* targetconshdlr;
10499  SCIP_EXPR* targetexpr = NULL;
10500  SCIP_CONSDATA* sourcedata;
10501 
10502  assert(cons != NULL);
10503 
10504  sourcedata = SCIPconsGetData(sourcecons);
10505  assert(sourcedata != NULL);
10506 
10507  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10508  assert(targetconshdlr != NULL);
10509 
10510  SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
10511 
10512  if( targetexpr == NULL )
10513  *valid = FALSE;
10514 
10515  *cons = NULL;
10516  if( *valid )
10517  {
10518  /* create copy (only capture targetexpr, no need to copy again) */
10519  SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
10520  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
10521  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10522  }
10523 
10524  if( targetexpr != NULL )
10525  {
10526  /* release target expr */
10527  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
10528  }
10529 
10530  return SCIP_OKAY;
10531 }
10532 
10533 
10534 /** constraint parsing method of constraint handler */
10535 static
10536 SCIP_DECL_CONSPARSE(consParseNonlinear)
10537 { /*lint --e{715}*/
10538  SCIP_Real lhs;
10539  SCIP_Real rhs;
10540  const char* endptr;
10541  SCIP_EXPR* consexprtree;
10542 
10543  SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
10544 
10545  assert(scip != NULL);
10546  assert(success != NULL);
10547  assert(str != NULL);
10548  assert(name != NULL);
10549  assert(cons != NULL);
10550 
10551  *success = FALSE;
10552 
10553  /* return if string empty */
10554  if( !*str )
10555  return SCIP_OKAY;
10556 
10557  endptr = str;
10558 
10559  /* set left and right hand side to their default values */
10560  lhs = -SCIPinfinity(scip);
10561  rhs = SCIPinfinity(scip);
10562 
10563  /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
10564 
10565  /* check for left hand side */
10566  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
10567  {
10568  /* there is a number coming, maybe it is a left-hand-side */
10569  if( !SCIPstrToRealValue(str, &lhs, (char**)&endptr) )
10570  {
10571  SCIPerrorMessage("error parsing number from <%s>\n", str);
10572  return SCIP_READERROR;
10573  }
10574 
10575  /* ignore whitespace */
10576  while( isspace((unsigned char)*endptr) )
10577  ++endptr;
10578 
10579  if( endptr[0] != '<' || endptr[1] != '=' )
10580  {
10581  /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
10582  lhs = -SCIPinfinity(scip);
10583  }
10584  else
10585  {
10586  /* it was indeed a left-hand-side, so continue parsing after it */
10587  str = endptr + 2;
10588 
10589  /* ignore whitespace */
10590  while( isspace((unsigned char)*str) )
10591  ++str;
10592  }
10593  }
10594 
10595  SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
10596 
10597  /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
10598  SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
10599 
10600  /* check for left or right hand side */
10601  while( isspace((unsigned char)*str) )
10602  ++str;
10603 
10604  /* check for free constraint */
10605  if( strncmp(str, "[free]", 6) == 0 )
10606  {
10607  if( !SCIPisInfinity(scip, -lhs) )
10608  {
10609  SCIPerrorMessage("cannot have left hand side and [free] status \n");
10610  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10611  return SCIP_OKAY;
10612  }
10613  *success = TRUE;
10614  }
10615  else
10616  {
10617  switch( *str )
10618  {
10619  case '<':
10620  *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10621  break;
10622  case '=':
10623  if( !SCIPisInfinity(scip, -lhs) )
10624  {
10625  SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
10626  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10627  return SCIP_OKAY;
10628  }
10629  else
10630  {
10631  *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10632  lhs = rhs;
10633  }
10634  break;
10635  case '>':
10636  if( !SCIPisInfinity(scip, -lhs) )
10637  {
10638  SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
10639  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10640  return SCIP_OKAY;
10641  }
10642  else
10643  {
10644  *success = SCIPstrToRealValue(str+2, &lhs, (char**)&endptr);
10645  break;
10646  }
10647  case '\0':
10648  *success = TRUE;
10649  break;
10650  default:
10651  SCIPerrorMessage("unexpected character %c\n", *str);
10652  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10653  return SCIP_OKAY;
10654  }
10655  }
10656 
10657  /* create constraint */
10658  SCIP_CALL( createCons(scip, conshdlr, cons, name,
10659  consexprtree, lhs, rhs, FALSE,
10660  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10661  assert(*cons != NULL);
10662 
10663  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10664 
10665  SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
10666 
10667  return SCIP_OKAY;
10668 }
10669 
10670 
10671 /** constraint method of constraint handler which returns the variables (if possible) */
10672 static
10673 SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
10674 { /*lint --e{715}*/
10675  SCIP_CONSDATA* consdata;
10676  int i;
10677 
10678  consdata = SCIPconsGetData(cons);
10679  assert(consdata != NULL);
10680 
10681  /* store variable expressions if not done so far */
10682  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10683 
10684  /* check whether array is too small in order to store all variables */
10685  if( varssize < consdata->nvarexprs )
10686  {
10687  *success = FALSE;
10688  return SCIP_OKAY;
10689  }
10690 
10691  for( i = 0; i < consdata->nvarexprs; ++i )
10692  {
10693  vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
10694  assert(vars[i] != NULL);
10695  }
10696 
10697  *success = TRUE;
10698 
10699  return SCIP_OKAY;
10700 }
10701 
10702 /** constraint method of constraint handler which returns the number of variables (if possible) */
10703 static
10704 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
10705 { /*lint --e{715}*/
10706  SCIP_CONSDATA* consdata;
10707 
10708  consdata = SCIPconsGetData(cons);
10709  assert(consdata != NULL);
10710 
10711  /* store variable expressions if not done so far */
10712  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10713 
10714  *nvars = consdata->nvarexprs;
10715  *success = TRUE;
10716 
10717  return SCIP_OKAY;
10718 }
10719 
10720 /** constraint handler method to suggest dive bound changes during the generic diving algorithm */
10721 #ifdef SCIP_DISABLED_CODE
10722 static
10724 { /*lint --e{715}*/
10725  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10726  SCIPABORT(); /*lint --e{527}*/
10727 
10728  return SCIP_OKAY;
10729 }
10730 #else
10731 #define consGetDiveBdChgsNonlinear NULL
10732 #endif
10733 
10734 /** output method of statistics table to output file stream 'file' */
10735 static
10736 SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
10737 { /*lint --e{715}*/
10738  SCIP_CONSHDLR* conshdlr;
10739  SCIP_CONSHDLRDATA* conshdlrdata;
10740 
10741  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10742  assert(conshdlr != NULL);
10743 
10744  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10745  assert(conshdlrdata != NULL);
10746 
10747  /* print statistics for constraint handler */
10748  SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
10749  SCIPinfoMessage(scip, file, " enforce%-10s:", "");
10750  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
10751  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
10752  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
10753  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
10754  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
10755  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
10756  SCIPinfoMessage(scip, file, "\n");
10757  SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
10758  SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
10759  SCIPinfoMessage(scip, file, "\n");
10760 
10761  return SCIP_OKAY;
10762 }
10763 
10764 /** output method of statistics table to output file stream 'file' */
10765 static
10766 SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
10767 { /*lint --e{715}*/
10768  SCIP_CONSHDLR* conshdlr;
10769  SCIP_CONSHDLRDATA* conshdlrdata;
10770 
10771  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10772  assert(conshdlr != NULL);
10773 
10774  /* skip nlhdlr table if there never were active nonlinear constraints */
10775  if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
10776  return SCIP_OKAY;
10777 
10778  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10779  assert(conshdlrdata != NULL);
10780 
10781  /* print statistics for nonlinear handlers */
10782  SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
10783 
10784  return SCIP_OKAY;
10785 }
10786 
10787 /** execution method of display nlhdlrs dialog */
10788 static
10789 SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
10790 { /*lint --e{715}*/
10791  SCIP_CONSHDLR* conshdlr;
10792  SCIP_CONSHDLRDATA* conshdlrdata;
10793  int i;
10794 
10795  /* add dialog to history of dialogs that have been executed */
10796  SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
10797 
10798  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10799  assert(conshdlr != NULL);
10800 
10801  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10802  assert(conshdlrdata != NULL);
10803 
10804  /* display list of nonlinear handler */
10805  SCIPdialogMessage(scip, NULL, "\n");
10806  SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
10807  SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
10808  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10809  {
10810  SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
10811  assert(nlhdlr != NULL);
10812 
10813  SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
10814  SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
10815  SCIPdialogMessage(scip, NULL, " %10d ", SCIPnlhdlrGetDetectPriority(nlhdlr));
10816  SCIPdialogMessage(scip, NULL, " %11d ", SCIPnlhdlrGetEnfoPriority(nlhdlr));
10817  SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
10818  SCIPdialogMessage(scip, NULL, "\n");
10819  }
10820  SCIPdialogMessage(scip, NULL, "\n");
10821 
10822  /* next dialog will be root dialog again */
10823  *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
10824 
10825  return SCIP_OKAY;
10826 }
10827 
10828 /*
10829  * constraint handler specific interface methods
10830  */
10831 
10832 /** creates the handler for nonlinear constraints and includes it in SCIP */
10834  SCIP* scip /**< SCIP data structure */
10835  )
10836 {
10837  SCIP_CONSHDLRDATA* conshdlrdata;
10838  SCIP_DIALOG* parentdialog;
10839 
10840  /* create nonlinear constraint handler data */
10841  SCIP_CALL( SCIPallocClearMemory(scip, &conshdlrdata) );
10842  conshdlrdata->intevalvar = intEvalVarBoundTightening;
10843  conshdlrdata->curboundstag = 1;
10844  conshdlrdata->lastboundrelax = 1;
10845  conshdlrdata->curpropboundstag = 1;
10846  conshdlrdata->newsoleventfilterpos = -1;
10847  SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
10848  SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
10849  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
10850 
10851  /* include constraint handler */
10857  conshdlrCopyNonlinear,
10858  consFreeNonlinear, consInitNonlinear, consExitNonlinear,
10859  consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
10860  consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
10861  consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
10862  consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
10863  consActiveNonlinear, consDeactiveNonlinear,
10864  consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
10865  consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
10866  consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, conshdlrdata) );
10867 
10868  /* add nonlinear constraint handler parameters */
10869  /* TODO organize into more subcategories */
10870  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
10871  "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
10872  &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
10873 
10874  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
10875  "whether to check bounds of all auxiliary variable to seed reverse propagation",
10876  &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
10877 
10878  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
10879  "strategy on how to relax variable bounds during bound tightening: relax (n)ot, relax by (a)bsolute value, relax always by a(b)solute value, relax by (r)relative value",
10880  &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
10881 
10882  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
10883  "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
10884  &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10885 
10886  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
10887  "by how much to relax constraint sides during bound tightening",
10888  &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10889 
10890  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
10891  "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
10892  &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
10893 
10894  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
10895  "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
10896  &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
10897 
10898  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
10899  "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
10900  &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
10901 
10902  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
10903  "maximal number of auxiliary expressions per bilinear term",
10904  &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
10905 
10906  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
10907  "whether to reformulate products of binary variables during presolving",
10908  &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
10909 
10910  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
10911  "whether to use the AND constraint handler for reformulating binary products",
10912  &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
10913 
10914  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
10915  "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
10916  &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
10917 
10918  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
10919  "whether to forbid multiaggregation of nonlinear variables",
10920  &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
10921 
10922  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
10923  "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
10924  &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
10925 
10926  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
10927  "whether to (re)run propagation in enforcement",
10928  &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
10929 
10930  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
10931  "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
10932  &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
10933 
10934  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
10935  "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
10936  &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
10937 
10938  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
10939  "consider efficacy requirement when deciding whether a cut is \"strong\"",
10940  &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
10941 
10942  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
10943  "whether to force \"strong\" cuts in enforcement",
10944  &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
10945 
10946  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
10947  "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
10948  &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
10949 
10950  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
10951  "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
10952  &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
10953 
10954  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
10955  "whether to make rows to be non-removable in the node where they are added (can prevent some cycling): 'o'ff, in 'e'nforcement only, 'a'lways",
10956  &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
10957 
10958  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
10959  "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
10960  &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
10961 
10962  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
10963  "whether variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction)",
10964  &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
10965 
10966  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
10967  "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
10968  &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
10969 
10970  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
10971  "whether to use external branching candidates and branching rules for branching",
10972  &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
10973 
10974  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
10975  "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
10976  &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
10977 
10978  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
10979  "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
10980  &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
10981 
10982  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
10983  "weight by how much to consider the violation assigned to a variable for its branching score",
10984  &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10985 
10986  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
10987  "weight by how much to consider the dual values of rows that contain a variable for its branching score",
10988  &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10989 
10990  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
10991  "weight by how much to consider the pseudo cost of a variable for its branching score",
10992  &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10993 
10994  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
10995  "weight by how much to consider the domain width in branching score",
10996  &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10997 
10998  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
10999  "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
11000  &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
11001 
11002  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
11003  "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
11004  &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
11005 
11006  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
11007  "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
11008  &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
11009 
11010  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
11011  "minimum pseudo-cost update count required to consider pseudo-costs reliable",
11012  &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11013 
11014  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
11015  "whether tight linearizations of nonlinear constraints should be added to cutpool when some heuristics finds a new solution ('o'ff, on new 'i'ncumbents, on 'e'very solution)",
11016  &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
11017 
11018  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
11019  "whether to assume that any constraint is convex",
11020  &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
11021 
11022  /* include handler for bound change events */
11023  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
11024  "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
11025  assert(conshdlrdata->eventhdlr != NULL);
11026 
11027  /* include tables for statistics */
11028  assert(SCIPfindTable(scip, TABLE_NAME_NONLINEAR) == NULL);
11030  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
11032 
11033  assert(SCIPfindTable(scip, TABLE_NAME_NLHDLR) == NULL);
11035  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
11037 
11038  /* create, include, and release display nlhdlrs dialog */
11039  if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
11040  {
11041  SCIP_DIALOG* dialog;
11042 
11043  assert(parentdialog != NULL);
11044  assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
11045 
11046  SCIP_CALL( SCIPincludeDialog(scip, &dialog,
11047  NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
11049  SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
11050  SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
11051  }
11052 
11053  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
11054  processNewSolutionEvent, NULL) );
11055 
11056  return SCIP_OKAY;
11057 }
11058 
11059 /** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
11061  SCIP* scip, /**< SCIP data structure */
11062  SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
11063  int priority, /**< priority of upgrading method */
11064  SCIP_Bool active, /**< should the upgrading method by active by default? */
11065  const char* conshdlrname /**< name of the constraint handler */
11066  )
11067 {
11068  SCIP_CONSHDLR* conshdlr;
11069  SCIP_CONSHDLRDATA* conshdlrdata;
11070  CONSUPGRADE* consupgrade;
11071  char paramname[SCIP_MAXSTRLEN];
11072  char paramdesc[SCIP_MAXSTRLEN];
11073  int i;
11074 
11075  assert(conshdlrname != NULL );
11076  assert(nlconsupgd != NULL);
11077 
11078  /* find the nonlinear constraint handler */
11079  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11080  if( conshdlr == NULL )
11081  {
11082  SCIPerrorMessage("nonlinear constraint handler not found\n");
11083  return SCIP_PLUGINNOTFOUND;
11084  }
11085 
11086  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11087  assert(conshdlrdata != NULL);
11088 
11089  /* check whether upgrade method exists already */
11090  for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
11091  {
11092  if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
11093  {
11094 #ifdef SCIP_DEBUG
11095  SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
11096 #endif
11097  return SCIP_OKAY;
11098  }
11099  }
11100 
11101  /* create a nonlinear constraint upgrade data object */
11102  SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
11103  consupgrade->consupgd = nlconsupgd;
11104  consupgrade->priority = priority;
11105  consupgrade->active = active;
11106 
11107  /* insert nonlinear constraint upgrade method into constraint handler data */
11108  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
11109  assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
11110 
11111  for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
11112  conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
11113  assert(0 <= i && i <= conshdlrdata->nconsupgrades);
11114  conshdlrdata->consupgrades[i] = consupgrade;
11115  conshdlrdata->nconsupgrades++;
11116 
11117  /* adds parameter to turn on and off the upgrading step */
11118  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
11119  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
11121  paramname, paramdesc,
11122  &consupgrade->active, FALSE, active, NULL, NULL) );
11123 
11124  return SCIP_OKAY;
11125 }
11126 
11127 /** creates and captures a nonlinear constraint
11128  *
11129  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11130  */
11132  SCIP* scip, /**< SCIP data structure */
11133  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11134  const char* name, /**< name of constraint */
11135  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11136  SCIP_Real lhs, /**< left hand side of constraint */
11137  SCIP_Real rhs, /**< right hand side of constraint */
11138  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11139  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11140  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11141  * Usually set to TRUE. */
11142  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11143  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11144  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11145  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11146  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11147  * Usually set to TRUE. */
11148  SCIP_Bool local, /**< is constraint only valid locally?
11149  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11150  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11151  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11152  * adds coefficients to this constraint. */
11153  SCIP_Bool dynamic, /**< is constraint subject to aging?
11154  * Usually set to FALSE. Set to TRUE for own cuts which
11155  * are separated as constraints. */
11156  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11157  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11158  )
11159 {
11160  /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
11161  SCIP_CONSHDLR* conshdlr;
11162 
11163  /* find the nonlinear constraint handler */
11164  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11165  if( conshdlr == NULL )
11166  {
11167  SCIPerrorMessage("nonlinear constraint handler not found\n");
11168  return SCIP_PLUGINNOTFOUND;
11169  }
11170 
11171  /* create constraint */
11172  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
11173  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11174 
11175  return SCIP_OKAY;
11176 }
11177 
11178 /** creates and captures a nonlinear constraint with all its constraint flags set to their default values
11179  *
11180  * All flags can be set via SCIPconsSetFLAGNAME-methods.
11181  *
11182  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
11183  *
11184  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11185  */
11187  SCIP* scip, /**< SCIP data structure */
11188  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11189  const char* name, /**< name of constraint */
11190  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11191  SCIP_Real lhs, /**< left hand side of constraint */
11192  SCIP_Real rhs /**< right hand side of constraint */
11193  )
11194 {
11195  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
11196  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11197 
11198  return SCIP_OKAY;
11199 }
11200 
11201 /** creates and captures a quadratic nonlinear constraint
11202  *
11203  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11204  */
11206  SCIP* scip, /**< SCIP data structure */
11207  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11208  const char* name, /**< name of constraint */
11209  int nlinvars, /**< number of linear terms */
11210  SCIP_VAR** linvars, /**< array with variables in linear part */
11211  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11212  int nquadterms, /**< number of quadratic terms */
11213  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11214  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11215  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11216  SCIP_Real lhs, /**< left hand side of quadratic equation */
11217  SCIP_Real rhs, /**< right hand side of quadratic equation */
11218  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11219  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11220  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11221  * Usually set to TRUE. */
11222  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11223  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11224  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11225  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11226  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11227  * Usually set to TRUE. */
11228  SCIP_Bool local, /**< is constraint only valid locally?
11229  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11230  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11231  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11232  * adds coefficients to this constraint. */
11233  SCIP_Bool dynamic, /**< is constraint subject to aging?
11234  * Usually set to FALSE. Set to TRUE for own cuts which
11235  * are separated as constraints. */
11236  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11237  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11238  )
11239 {
11240  SCIP_CONSHDLR* conshdlr;
11241  SCIP_EXPR* expr;
11242 
11243  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
11244  assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
11245 
11246  /* get nonlinear constraint handler */
11247  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11248  if( conshdlr == NULL )
11249  {
11250  SCIPerrorMessage("nonlinear constraint handler not found\n");
11251  return SCIP_PLUGINNOTFOUND;
11252  }
11253 
11254  /* create quadratic expression */
11255  SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
11256  assert(expr != NULL);
11257 
11258  /* create nonlinear constraint */
11259  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
11260  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11261 
11262  /* release quadratic expression (captured by constraint now) */
11263  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11264 
11265  return SCIP_OKAY;
11266 }
11267 
11268 /** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
11269  *
11270  * All flags can be set via SCIPconsSetFLAGNAME-methods.
11271  *
11272  * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
11273  *
11274  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11275  */
11277  SCIP* scip, /**< SCIP data structure */
11278  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11279  const char* name, /**< name of constraint */
11280  int nlinvars, /**< number of linear terms */
11281  SCIP_VAR** linvars, /**< array with variables in linear part */
11282  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11283  int nquadterms, /**< number of quadratic terms */
11284  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11285  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11286  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11287  SCIP_Real lhs, /**< left hand side of quadratic equation */
11288  SCIP_Real rhs /**< right hand side of quadratic equation */
11289  )
11290 {
11291  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11292  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11293 
11294  return SCIP_OKAY;
11295 }
11296 
11297 /** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
11298  *
11299  * \f$\sqrt{\gamma + \sum_{i=1}^{n} (\alpha_i\, (x_i + \beta_i))^2} \leq \alpha_{n+1}\, (x_{n+1}+\beta_{n+1})\f$
11300  *
11301  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11302  */
11304  SCIP* scip, /**< SCIP data structure */
11305  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11306  const char* name, /**< name of constraint */
11307  int nvars, /**< number of variables on left hand side of constraint (n) */
11308  SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
11309  SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
11310  SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
11311  SCIP_Real constant, /**< constant on left hand side (gamma) */
11312  SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
11313  SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
11314  SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
11315  )
11316 {
11317  SCIP_EXPR* expr;
11318  SCIP_EXPR* lhssum;
11319  SCIP_EXPR* terms[2];
11320  SCIP_Real termcoefs[2];
11321  int i;
11322 
11323  assert(vars != NULL || nvars == 0);
11324 
11325  SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
11326  for( i = 0; i < nvars; ++i )
11327  {
11328  SCIP_EXPR* varexpr;
11329  SCIP_EXPR* powexpr;
11330 
11331  SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
11332  if( offsets != NULL && offsets[i] != 0.0 )
11333  {
11334  SCIP_EXPR* sum;
11335  SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
11336  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
11337  SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
11338  }
11339  else
11340  {
11341  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
11342  }
11343 
11344  SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
11345  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
11346  SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
11347  }
11348 
11349  SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
11350  SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
11351  termcoefs[0] = 1.0;
11352 
11353  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
11354  termcoefs[1] = -rhscoeff;
11355 
11356  SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
11357 
11358  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11359  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11360 
11361  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
11362 
11363  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11364 
11365  return SCIP_OKAY;
11366 }
11367 
11368 /** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
11369  *
11370  * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
11371  *
11372  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11373  */
11375  SCIP* scip, /**< SCIP data structure */
11376  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11377  const char* name, /**< name of constraint */
11378  SCIP_VAR* x, /**< nonlinear variable x in constraint */
11379  SCIP_VAR* z, /**< linear variable z in constraint */
11380  SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
11381  SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
11382  SCIP_Real zcoef, /**< coefficient of z in constraint */
11383  SCIP_Real lhs, /**< left hand side of constraint */
11384  SCIP_Real rhs /**< right hand side of constraint */
11385  )
11386 {
11387  SCIP_EXPR* xexpr;
11388  SCIP_EXPR* terms[2];
11389  SCIP_Real coefs[2];
11390  SCIP_EXPR* sumexpr;
11391 
11392  assert(x != NULL);
11393  assert(z != NULL);
11394 
11395  SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
11396  if( xoffset != 0.0 )
11397  {
11398  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
11399  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
11400 
11401  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11402  }
11403  else
11404  {
11405  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
11406  }
11407  coefs[0] = 1.0;
11408 
11409  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
11410  coefs[1] = zcoef;
11411 
11412  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
11413 
11414  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
11415 
11416  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11417  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11418  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11419  SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
11420 
11421  return SCIP_OKAY;
11422 }
11423 
11424 /** gets tag indicating current local variable bounds */
11426  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11427  )
11428 {
11429  SCIP_CONSHDLRDATA* conshdlrdata;
11430 
11431  assert(conshdlr != NULL);
11432  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11433 
11434  return conshdlrdata->curboundstag;
11435 }
11436 
11437 /** gets the `curboundstag` from the last time where variable bounds were relaxed */
11439  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11440  )
11441 {
11442  SCIP_CONSHDLRDATA* conshdlrdata;
11443 
11444  assert(conshdlr != NULL);
11445  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11446 
11447  return conshdlrdata->lastboundrelax;
11448 }
11449 
11450 /** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
11451  *
11452  * @attention This method is not intended for normal use.
11453  * These tags are maintained by the event handler for variable bound change events.
11454  * This method is used by some unittests.
11455  */
11457  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11458  SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
11459  )
11460 {
11461  SCIP_CONSHDLRDATA* conshdlrdata;
11462 
11463  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11464  assert(conshdlrdata != NULL);
11465 
11466  ++conshdlrdata->curboundstag;
11467  assert(conshdlrdata->curboundstag > 0);
11468 
11469  if( boundrelax )
11470  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
11471 }
11472 
11473 /** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
11475  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11476  )
11477 {
11478  assert(conshdlr != NULL);
11479 
11480  return SCIPconshdlrGetData(conshdlr)->var2expr;
11481 }
11482 
11483 /** processes a rowprep for cut addition and maybe report branchscores */
11485  SCIP* scip, /**< SCIP data structure */
11486  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
11487  SCIP_CONS* cons, /**< nonlinear constraint */
11488  SCIP_EXPR* expr, /**< expression */
11489  SCIP_ROWPREP* rowprep, /**< cut to be added */
11490  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
11491  SCIP_VAR* auxvar, /**< auxiliary variable */
11492  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
11493  SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
11494  SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
11495  SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
11496  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
11497  SCIP_RESULT* result /**< pointer to store the result */
11498  )
11499 {
11500  SCIP_Real cutviol;
11501  SCIP_CONSHDLRDATA* conshdlrdata;
11502  SCIP_Real auxvarvalue = SCIP_INVALID;
11503  SCIP_Bool sepasuccess;
11504  SCIP_Real estimateval = SCIP_INVALID;
11505  SCIP_Real mincutviolation;
11506 
11507  assert(nlhdlr != NULL);
11508  assert(cons != NULL);
11509  assert(expr != NULL);
11510  assert(rowprep != NULL);
11511  assert(auxvar != NULL);
11512  assert(result != NULL);
11513 
11514  /* decide on minimal violation of cut */
11515  if( sol == NULL )
11516  mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
11517  else
11518  mincutviolation = SCIPfeastol(scip);
11519 
11520  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11521  assert(conshdlrdata != NULL);
11522 
11523  sepasuccess = TRUE;
11524 
11525  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
11526  if( cutviol > 0.0 )
11527  {
11528  auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
11529 
11530  /* check whether cut is weak (if f(x) not defined, then it's never weak) */
11531  if( !allowweakcuts && auxvalue != SCIP_INVALID )
11532  {
11533  /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
11534  * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
11535  * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
11536  * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
11537  * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
11538  * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
11539  *
11540  * if we are overestimating, we have z >= c'x-b >= f(x)
11541  * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
11542  * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
11543  * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
11544  *
11545  * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
11546  */
11547  if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11548  ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11549  {
11550  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
11551  "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11552  SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11553  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
11554  sepasuccess = FALSE;
11555  }
11556  }
11557 
11558  /* save estimator value for later, see long comment above why this gives the value for c'x-b */
11559  estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
11560  }
11561  else
11562  {
11563  sepasuccess = FALSE;
11564  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
11565  "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
11566  }
11567 
11568  /* clean up estimator */
11569  if( sepasuccess )
11570  {
11571  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
11572  "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11573  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
11574  SCIPprintRowprep(scip, rowprep, enfologfile); )
11575 
11576  /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
11577  * instead, may even scale them down, that is, scale so that max coef is close to 1
11578  */
11579  if( !allowweakcuts )
11580  {
11581  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
11582 
11583  if( !sepasuccess )
11584  {
11585  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
11586  }
11587  else
11588  {
11589  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
11590  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
11591  "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
11592  if( sepasuccess )
11593  sepasuccess = cutviol > mincutviolation;
11594  }
11595 
11596  if( sepasuccess && auxvalue != SCIP_INVALID )
11597  {
11598  /* check whether cut is weak now
11599  * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
11600  * reconstructing estimateval from cutviol (TODO improve or remove?)
11601  */
11602  SCIP_Real auxvarcoef = 0.0;
11603  int i;
11604 
11605  /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
11606  * it should be...
11607  */
11608  for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
11609  {
11610  if( SCIProwprepGetVars(rowprep)[i] == auxvar )
11611  {
11612  auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
11613  break;
11614  }
11615  }
11616 
11617  if( auxvarcoef == 0.0 ||
11618  (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11619  ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11620  {
11621  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11622  auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
11623  sepasuccess = FALSE;
11624  }
11625  }
11626  }
11627  else
11628  {
11629  /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
11630 
11631  /* if estimate didn't report branchscores explicitly, then consider branching on those children for
11632  * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
11633  */
11634  if( !branchscoresuccess )
11636 
11637  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
11638 
11639  if( !sepasuccess )
11640  {
11641  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
11642  SCIProwprepGetNModifiedVars(rowprep), cutviol); )
11643  }
11644 
11645  /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
11646  * changed
11647  */
11648  if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
11649  {
11650  SCIP_Real violscore;
11651 
11652 #ifdef BRSCORE_ABSVIOL
11653  violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
11654 #else
11655  SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
11656 #endif
11657  SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
11658 
11659  /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
11660  * - were fixed,
11661  * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
11662  * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
11663  * the first case came up again in #3085 and I don't see how to exclude this in the assert,
11664  * so I'm disabling the assert for now
11665  */
11666  /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
11667  strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
11668  }
11669  }
11670  }
11671 
11672  /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
11673  if( sepasuccess )
11674  {
11675  SCIP_ROW* row;
11676 
11677  if( conshdlrdata->branchdualweight > 0.0 )
11678  {
11679  /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
11680  * skip if gap is zero
11681  */
11682  if( auxvalue == SCIP_INVALID )
11683  strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
11684  else if( !SCIPisEQ(scip, auxvalue, estimateval) )
11685  {
11686  char gap[40];
11687  (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
11688  strcat(SCIProwprepGetName(rowprep), gap);
11689  }
11690  }
11691 
11692  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
11693 
11694  if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
11695  {
11696  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
11697  SCIPgetCutEfficacy(scip, sol, row), SCIPgetSepaMinEfficacy(scip)); )
11698  }
11699  else if( !SCIPisCutApplicable(scip, row) )
11700  {
11701  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
11702  }
11703  else
11704  {
11705  SCIP_Bool infeasible;
11706 
11707  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
11708  SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
11709 
11710  /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
11711  * if we haven't found strong cuts before)
11712  */
11713  SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
11714 
11715  /* mark row as not removable from LP for current node (this can prevent some cycling) */
11716  if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
11717  SCIPmarkRowNotRemovableLocal(scip, row);
11718 
11719  if( infeasible )
11720  {
11721  *result = SCIP_CUTOFF;
11723  }
11724  else
11725  {
11726  *result = SCIP_SEPARATED;
11728  }
11729  }
11730 
11731  SCIP_CALL( SCIPreleaseRow(scip, &row) );
11732  }
11733  else if( branchscoresuccess )
11734  {
11735  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
11736  "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
11737 
11738  /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
11739  * expressions eligible for branching candidate, see enforceConstraints() and branching()
11740  */
11741  *result = SCIP_BRANCHED;
11742  }
11743  else
11744  {
11745  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
11746  "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
11747  " (!)" : ""); )
11748  }
11749 
11750  return SCIP_OKAY;
11751 }
11752 
11753 /** returns whether all nonlinear constraints are assumed to be convex */
11755  SCIP_CONSHDLR* conshdlr
11756  )
11757 {
11758  SCIP_CONSHDLRDATA* conshdlrdata;
11759 
11760  assert(conshdlr != NULL);
11761 
11762  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11763  assert(conshdlrdata != NULL);
11764 
11765  return conshdlrdata->assumeconvex;
11766 }
11767 
11768 /** collects all bilinear terms for a given set of constraints
11769  *
11770  * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
11771  * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
11772  */
11774  SCIP* scip, /**< SCIP data structure */
11775  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11776  SCIP_CONS** conss, /**< nonlinear constraints */
11777  int nconss /**< total number of nonlinear constraints */
11778  )
11779 {
11780  assert(conshdlr != NULL);
11781  assert(conss != NULL || nconss == 0);
11782 
11783  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11784 
11785  return SCIP_OKAY;
11786 }
11787 
11788 /** returns the total number of bilinear terms that are contained in all nonlinear constraints
11789  *
11790  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11791  */
11793  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11794  )
11795 {
11796  SCIP_CONSHDLRDATA* conshdlrdata;
11797 
11798  assert(conshdlr != NULL);
11799 
11800  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11801  assert(conshdlrdata != NULL);
11802 
11803  return conshdlrdata->nbilinterms;
11804 }
11805 
11806 /** returns all bilinear terms that are contained in all nonlinear constraints
11807  *
11808  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11809  * @note The value of the auxiliary variable of a bilinear term might be NULL, which indicates that the term does not have an auxiliary variable.
11810  */
11812  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11813  )
11814 {
11815  SCIP_CONSHDLRDATA* conshdlrdata;
11816 
11817  assert(conshdlr != NULL);
11818 
11819  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11820  assert(conshdlrdata != NULL);
11821 
11822  return conshdlrdata->bilinterms;
11823 }
11824 
11825 /** returns the index of the bilinear term representing the product of the two given variables
11826  *
11827  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11828  * @return The method returns -1 if the variables do not appear bilinearly.
11829  */
11831  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11832  SCIP_VAR* x, /**< first variable */
11833  SCIP_VAR* y /**< second variable */
11834  )
11835 {
11836  SCIP_CONSHDLRDATA* conshdlrdata;
11838  int idx;
11839 
11840  assert(conshdlr != NULL);
11841  assert(x != NULL);
11842  assert(y != NULL);
11843 
11844  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11845  assert(conshdlrdata != NULL);
11846 
11847  if( conshdlrdata->bilinhashtable == NULL )
11848  {
11849  return -1;
11850  }
11851 
11852  /* ensure that x.index <= y.index */
11853  if( SCIPvarCompare(x, y) == 1 )
11854  {
11855  SCIPswapPointers((void**)&x, (void**)&y);
11856  }
11857  assert(SCIPvarCompare(x, y) < 1);
11858 
11859  /* use a new entry to find the image in the bilinear hash table */
11860  entry.x = x;
11861  entry.y = y;
11862  idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
11863  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11864  assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
11865  assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
11866 
11867  return idx;
11868 }
11869 
11870 /** returns the bilinear term that represents the product of two given variables
11871  *
11872  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11873  * @return The method returns NULL if the variables do not appear bilinearly.
11874  */
11876  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11877  SCIP_VAR* x, /**< first variable */
11878  SCIP_VAR* y /**< second variable */
11879  )
11880 {
11881  SCIP_CONSHDLRDATA* conshdlrdata;
11882  int idx;
11883 
11884  assert(conshdlr != NULL);
11885  assert(x != NULL);
11886  assert(y != NULL);
11887 
11888  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11889  assert(conshdlrdata != NULL);
11890 
11891  idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
11892  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11893 
11894  if( idx >= 0 )
11895  {
11896  return &conshdlrdata->bilinterms[idx];
11897  }
11898 
11899  return NULL;
11900 }
11901 
11902 /** evaluates an auxiliary expression for a bilinear term */
11904  SCIP* scip, /**< SCIP data structure */
11905  SCIP_VAR* x, /**< first variable of the bilinear term */
11906  SCIP_VAR* y, /**< second variable of the bilinear term */
11907  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
11908  SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
11909  )
11910 {
11911  assert(scip != NULL);
11912  assert(x != NULL);
11913  assert(y != NULL);
11914  assert(auxexpr != NULL);
11915  assert(auxexpr->auxvar != NULL);
11916 
11917  return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
11918  auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
11919 }
11920 
11921 /** stores the variables of a bilinear term in the data of the constraint handler */
11923  SCIP* scip, /**< SCIP data structure */
11924  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11925  SCIP_VAR* x, /**< first variable */
11926  SCIP_VAR* y, /**< second variable */
11927  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11928  int nlockspos, /**< number of positive expression locks */
11929  int nlocksneg /**< number of negative expression locks */
11930  )
11931 {
11932  SCIP_CONSHDLRDATA* conshdlrdata;
11934  int idx;
11935 
11936  assert(conshdlr != NULL);
11937 
11938  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11939  assert(conshdlrdata != NULL);
11940 
11941  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
11942 
11943  term = &conshdlrdata->bilinterms[idx];
11944  assert(term != NULL);
11945  assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
11946  assert(term->aux.var == NULL); /* there should not already be an auxvar, that is, existing terms should exist only once (common subexprs should have been eliminated) */
11947 
11948  /* store and capture auxiliary variable */
11949  if( auxvar != NULL )
11950  {
11951  term->aux.var = auxvar;
11952  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
11953  }
11954 
11955  return SCIP_OKAY;
11956 }
11957 
11958 /** stores the variables of a bilinear term in the data of the constraint handler */
11960  SCIP* scip, /**< SCIP data structure */
11961  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11962  SCIP_VAR* x, /**< first variable */
11963  SCIP_VAR* y, /**< second variable */
11964  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11965  SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
11966  SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
11967  SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
11968  SCIP_Real cst, /**< constant of the auxiliary expression */
11969  SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
11970  )
11971 {
11972  SCIP_CONSHDLRDATA* conshdlrdata;
11974  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr;
11975  int idx;
11976  int nlockspos;
11977  int nlocksneg;
11978  SCIP_Bool added;
11979 
11980  assert(conshdlr != NULL);
11981 
11982  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11983  assert(conshdlrdata != NULL);
11984 
11985  nlockspos = overestimate ? 1 : 0;
11986  nlocksneg = overestimate ? 0 : 1;
11987 
11988  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
11989 
11990  term = &conshdlrdata->bilinterms[idx];
11991  assert(term != NULL);
11992  assert(SCIPvarCompare(term->x, term->y) < 1);
11993 
11994  if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
11995  {
11996  SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
11997  /* this is the case where we are adding an implicitly defined relation for a product that has already
11998  * been explicitly defined; convert auxvar into an auxexpr */
11999 
12000  /* nothing to do if we aren't allowed to add more than one auxexpr per term */
12001  if( conshdlrdata->bilinmaxnauxexprs <= 1 )
12002  return SCIP_OKAY;
12003 
12004  SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
12005  auxvarexpr->cst = 0.0;
12006  auxvarexpr->coefs[0] = 1.0;
12007  auxvarexpr->coefs[1] = 0.0;
12008  auxvarexpr->coefs[2] = 0.0;
12009  auxvarexpr->auxvar = term->aux.var;
12010  auxvarexpr->underestimate = term->nlocksneg > 0;
12011  auxvarexpr->overestimate = term->nlockspos > 0;
12012 
12013  /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
12014  term->aux.exprs = NULL;
12015 
12016  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
12017 
12018  /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
12019  assert(added);
12020  }
12021 
12022  /* create and add auxexpr */
12023  SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
12024  auxexpr->underestimate = !overestimate;
12025  auxexpr->overestimate = overestimate;
12026  auxexpr->auxvar = auxvar;
12027  auxexpr->coefs[0] = coefaux;
12028  if( term->x == x )
12029  {
12030  assert(term->y == y);
12031  auxexpr->coefs[1] = coefx;
12032  auxexpr->coefs[2] = coefy;
12033  }
12034  else
12035  {
12036  assert(term->x == y);
12037  assert(term->y == x);
12038  auxexpr->coefs[1] = coefy;
12039  auxexpr->coefs[2] = coefx;
12040  }
12041  auxexpr->cst = cst;
12042  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
12043 
12044  if( !added )
12045  {
12046  SCIPfreeBlockMemory(scip, &auxexpr);
12047  }
12048  else if( auxvar != NULL )
12049  { /* capture auxiliary variable */
12050  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
12051  }
12052 
12053  return SCIP_OKAY;
12054 }
12055 
12056 /* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
12058  SCIP* scip, /**< SCIP data structure */
12059  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12060  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
12061  SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
12062  void* fundata, /**< data for function evaluation (can be NULL) */
12063  SCIP_Real* xstar, /**< point to be separated */
12064  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
12065  int nallvars, /**< half of the length of box */
12066  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
12067  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
12068  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
12069  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
12070  )
12071 {
12072  SCIP_Real* corner;
12073  SCIP_Real* funvals;
12074  int* nonfixedpos;
12075  SCIP_Real maxfaceterror;
12076  int nvars; /* number of nonfixed variables */
12077  unsigned int ncorners;
12078  unsigned int i;
12079  int j;
12080 
12081  assert(scip != NULL);
12082  assert(conshdlr != NULL);
12083  assert(function != NULL);
12084  assert(xstar != NULL);
12085  assert(box != NULL);
12086  assert(success != NULL);
12087  assert(facetcoefs != NULL);
12088  assert(facetconstant != NULL);
12089 
12090  *success = FALSE;
12091 
12092  /* identify fixed variables */
12093  SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
12094  nvars = 0;
12095  for( j = 0; j < nallvars; ++j )
12096  {
12097  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12098  continue;
12099  nonfixedpos[nvars] = j;
12100  nvars++;
12101  }
12102 
12103  /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
12104  * if too many variables are not fixed, then we do nothing currently
12105  */
12106  if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
12107  {
12108  SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
12109  SCIPfreeBufferArray(scip, &nonfixedpos);
12110  return SCIP_OKAY;
12111  }
12112 
12113  /* compute f(v^i) for each corner v^i of [l,u] */
12114  ncorners = POWEROFTWO(nvars);
12115  SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
12116  SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
12117  for( j = 0; j < nallvars; ++j )
12118  {
12119  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12120  corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
12121  }
12122  for( i = 0; i < ncorners; ++i )
12123  {
12124  SCIPdebugMsg(scip, "corner %u: ", i);
12125  for( j = 0; j < nvars; ++j )
12126  {
12127  int varpos = nonfixedpos[j];
12128  /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
12129  * we check this by shifting i for j positions to the right and checking whether the last bit is set
12130  */
12131  if( (i >> j) & 0x1 )
12132  corner[varpos] = box[2 * varpos + 1]; /* ub of var */
12133  else
12134  corner[varpos] = box[2 * varpos ]; /* lb of var */
12135  SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
12136  assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
12137  }
12138 
12139  funvals[i] = function(corner, nallvars, fundata);
12140 
12141  SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
12142 
12143  if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
12144  {
12145  SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
12146  goto CLEANUP;
12147  }
12148  }
12149 
12150  /* clear coefs array; below we only fill in coefs for nonfixed variables */
12151  BMSclearMemoryArray(facetcoefs, nallvars);
12152 
12153  if( nvars == 1 )
12154  {
12155  SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
12156 
12157  /* check whether target has been missed */
12158  if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
12159  {
12160  SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
12161  *success = FALSE;
12162  }
12163  }
12164  else if( nvars == 2 )
12165  {
12166  int idx1 = nonfixedpos[0];
12167  int idx2 = nonfixedpos[1];
12168  SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
12169  SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
12170  SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
12171  SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
12172  SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
12173  SCIP_Real coefs[2] = { 0.0, 0.0 };
12174 
12175  SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
12176 
12177  facetcoefs[idx1] = coefs[0];
12178  facetcoefs[idx2] = coefs[1];
12179  }
12180  else
12181  {
12182  SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
12183  }
12184  if( !*success )
12185  {
12186  SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
12187  goto CLEANUP;
12188  }
12189 
12190  /*
12191  * check and adjust facet with the algorithm of Rikun et al.
12192  */
12193 
12194  maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
12195 
12196  /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
12197  if( maxfaceterror > 0.0 )
12198  {
12199  SCIP_CONSHDLRDATA* conshdlrdata;
12200  SCIP_Real midval;
12201  SCIP_Real feastol;
12202 
12203  feastol = SCIPgetStage(scip) == SCIP_STAGE_SOLVING ? SCIPgetLPFeastol(scip) : SCIPfeastol(scip);
12204 
12205  /* evaluate function in middle point to get some idea for a scaling */
12206  for( j = 0; j < nvars; ++j )
12207  corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
12208  midval = function(corner, nallvars, fundata);
12209  if( midval == SCIP_INVALID )
12210  midval = 1.0;
12211 
12212  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12213  assert(conshdlrdata != NULL);
12214 
12215  /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
12216  if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
12217  {
12218  SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
12219  *success = FALSE;
12220  goto CLEANUP;
12221  }
12222 
12223  SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
12224 
12225  if( overestimate )
12226  *facetconstant += maxfaceterror;
12227  else
12228  *facetconstant -= maxfaceterror;
12229  }
12230 
12231  /* if we made it until here, then we have a nice facet */
12232  assert(*success);
12233 
12234 CLEANUP:
12235  /* free allocated memory */
12236  SCIPfreeBufferArray(scip, &corner);
12237  SCIPfreeBufferArray(scip, &funvals);
12238  SCIPfreeBufferArray(scip, &nonfixedpos);
12239 
12240  return SCIP_OKAY;
12241 }
12242 
12243 /*
12244  * constraint specific interface methods
12245  */
12246 
12247 /** returns the expression of the given nonlinear constraint */
12249  SCIP_CONS* cons /**< constraint data */
12250  )
12251 {
12252  SCIP_CONSDATA* consdata;
12253 
12254  assert(cons != NULL);
12255  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12256 
12257  consdata = SCIPconsGetData(cons);
12258  assert(consdata != NULL);
12259 
12260  return consdata->expr;
12261 }
12262 
12263 /** gets the left hand side of a nonlinear constraint */
12265  SCIP_CONS* cons /**< constraint data */
12266  )
12267 {
12268  SCIP_CONSDATA* consdata;
12269 
12270  assert(cons != NULL);
12271  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12272 
12273  consdata = SCIPconsGetData(cons);
12274  assert(consdata != NULL);
12275 
12276  return consdata->lhs;
12277 }
12278 
12279 /** gets the right hand side of a nonlinear constraint */
12281  SCIP_CONS* cons /**< constraint data */
12282  )
12283 {
12284  SCIP_CONSDATA* consdata;
12285 
12286  assert(cons != NULL);
12287  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12288 
12289  consdata = SCIPconsGetData(cons);
12290  assert(consdata != NULL);
12291 
12292  return consdata->rhs;
12293 }
12294 
12295 /** gets the nonlinear constraint as a nonlinear row representation. */
12297  SCIP* scip, /**< SCIP data structure */
12298  SCIP_CONS* cons, /**< constraint */
12299  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
12300  )
12301 {
12302  SCIP_CONSDATA* consdata;
12303 
12304  assert(cons != NULL);
12305  assert(nlrow != NULL);
12306  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12307 
12308  consdata = SCIPconsGetData(cons);
12309  assert(consdata != NULL);
12310 
12311  if( consdata->nlrow == NULL )
12312  {
12313  SCIP_CALL( createNlRow(scip, cons) );
12314  }
12315  assert(consdata->nlrow != NULL);
12316  *nlrow = consdata->nlrow;
12317 
12318  return SCIP_OKAY;
12319 }
12320 
12321 /** returns the curvature of the expression of a given nonlinear constraint
12322  *
12323  * @note The curvature information is computed during CONSINITSOL.
12324  */
12326  SCIP_CONS* cons /**< constraint data */
12327  )
12328 {
12329  SCIP_CONSDATA* consdata;
12330 
12331  assert(cons != NULL);
12332  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12333 
12334  consdata = SCIPconsGetData(cons);
12335  assert(consdata != NULL);
12336 
12337  return consdata->curv;
12338 }
12339 
12340 /** checks whether expression of constraint can be represented as quadratic form
12341  *
12342  * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
12343  * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
12344  * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
12345  */
12347  SCIP* scip, /**< SCIP data structure */
12348  SCIP_CONS* cons, /**< constraint data */
12349  SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
12350  )
12351 {
12352  SCIP_CONSDATA* consdata;
12353 
12354  assert(scip != NULL);
12355  assert(cons != NULL);
12356  assert(isquadratic != NULL);
12357  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12358 
12359  consdata = SCIPconsGetData(cons);
12360  assert(consdata != NULL);
12361  assert(consdata->expr != NULL);
12362 
12363  /* check whether constraint expression is quadratic in extended formulation */
12364  SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
12365 
12366  /* if not quadratic in non-extended formulation, then do indicate quadratic */
12367  if( *isquadratic )
12368  *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
12369 
12370  return SCIP_OKAY;
12371 }
12372 
12373 /** changes left-hand-side of a nonlinear constraint
12374  *
12375  * @attention This method can only be called in the problem stage.
12376  */
12378  SCIP* scip, /**< SCIP data structure */
12379  SCIP_CONS* cons, /**< constraint data */
12380  SCIP_Real lhs /**< new left-hand-side */
12381  )
12382 {
12383  SCIP_CONSDATA* consdata;
12384 
12385  assert(scip != NULL);
12386  assert(cons != NULL);
12387  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12388 
12389  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12390  {
12391  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12392  return SCIP_INVALIDCALL;
12393  }
12394 
12395  /* we should have an original constraint */
12396  assert(SCIPconsIsOriginal(cons));
12397 
12398  consdata = SCIPconsGetData(cons);
12399  assert(consdata != NULL);
12400 
12401  if( consdata->lhs == lhs )
12402  return SCIP_OKAY;
12403 
12404  consdata->lhs = lhs;
12405 
12406  /* not sure we care about any of these flags for original constraints */
12407  consdata->ispropagated = FALSE;
12408 
12409  return SCIP_OKAY;
12410 }
12411 
12412 /** changes right-hand-side of a nonlinear constraint
12413  *
12414  * @attention This method can only be called in the problem stage.
12415  */
12417  SCIP* scip, /**< SCIP data structure */
12418  SCIP_CONS* cons, /**< constraint data */
12419  SCIP_Real rhs /**< new right-hand-side */
12420  )
12421 {
12422  SCIP_CONSDATA* consdata;
12423 
12424  assert(scip != NULL);
12425  assert(cons != NULL);
12426  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12427 
12428  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12429  {
12430  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12431  return SCIP_INVALIDCALL;
12432  }
12433 
12434  /* we should have an original constraint */
12435  assert(SCIPconsIsOriginal(cons));
12436 
12437  consdata = SCIPconsGetData(cons);
12438  assert(consdata != NULL);
12439 
12440  if( consdata->rhs == rhs )
12441  return SCIP_OKAY;
12442 
12443  consdata->rhs = rhs;
12444 
12445  /* not sure we care about any of these flags for original constraints */
12446  consdata->ispropagated = FALSE;
12447 
12448  return SCIP_OKAY;
12449 }
12450 
12451 /** changes expression of a nonlinear constraint
12452  *
12453  * @attention This method can only be called in the problem stage.
12454  */
12456  SCIP* scip, /**< SCIP data structure */
12457  SCIP_CONS* cons, /**< constraint data */
12458  SCIP_EXPR* expr /**< new expression */
12459  )
12460 {
12461  SCIP_CONSHDLR* conshdlr;
12462  SCIP_CONSDATA* consdata;
12463 
12464  assert(scip != NULL);
12465  assert(cons != NULL);
12466  assert(expr != NULL);
12467 
12468  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12469  {
12470  SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
12471  return SCIP_INVALIDCALL;
12472  }
12473 
12474  /* we should have an original constraint */
12475  assert(SCIPconsIsOriginal(cons));
12476 
12477  conshdlr = SCIPconsGetHdlr(cons);
12478  assert(conshdlr != NULL);
12479  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12480 
12481  consdata = SCIPconsGetData(cons);
12482  assert(consdata != NULL);
12483  assert(consdata->expr != NULL);
12484 
12485  /* we should not have collected additional data for the expr
12486  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12487  */
12488  assert(consdata->nvarexprs == 0);
12489  assert(consdata->varexprs == NULL);
12490  assert(!consdata->catchedevents);
12491 
12492  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
12493 
12494  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12495  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12496 
12497  /* not sure we care about any of these flags for original constraints */
12498  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
12499  consdata->issimplified = FALSE;
12500  consdata->ispropagated = FALSE;
12501 
12502  return SCIP_OKAY;
12503 }
12504 
12505 /** adds coef * var to nonlinear constraint
12506  *
12507  * @attention This method can only be called in the problem stage.
12508  */
12510  SCIP* scip, /**< SCIP data structure */
12511  SCIP_CONS* cons, /**< constraint data */
12512  SCIP_VAR* var, /**< variable */
12513  SCIP_Real coef /**< coefficient */
12514  )
12515 {
12516  SCIP_CONSHDLR* conshdlr;
12517  SCIP_CONSDATA* consdata;
12518  SCIP_EXPR* varexpr;
12519 
12520  assert(scip != NULL);
12521  assert(cons != NULL);
12522 
12523  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12524  {
12525  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12526  return SCIP_INVALIDCALL;
12527  }
12528 
12529  /* we should have an original constraint */
12530  assert(SCIPconsIsOriginal(cons));
12531 
12532  if( coef == 0.0 )
12533  return SCIP_OKAY;
12534 
12535  conshdlr = SCIPconsGetHdlr(cons);
12536  assert(conshdlr != NULL);
12537  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12538 
12539  consdata = SCIPconsGetData(cons);
12540  assert(consdata != NULL);
12541  assert(consdata->expr != NULL);
12542 
12543  /* we should not have collected additional data for it
12544  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12545  */
12546  assert(consdata->nvarexprs == 0);
12547  assert(consdata->varexprs == NULL);
12548  assert(!consdata->catchedevents);
12549 
12550  SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
12551 
12552  /* append to sum, if consdata->expr is sum and not used anywhere else */
12553  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12554  {
12555  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
12556  }
12557  else
12558  {
12559  /* create new expression = 1 * consdata->expr + coef * var */
12560  SCIP_EXPR* children[2] = { consdata->expr, varexpr };
12561  SCIP_Real coefs[2] = { 1.0, coef };
12562 
12563  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12564 
12565  /* release old root expr */
12566  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12567  }
12568 
12569  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12570 
12571  /* not sure we care about any of these flags for original constraints */
12572  consdata->issimplified = FALSE;
12573  consdata->ispropagated = FALSE;
12574 
12575  return SCIP_OKAY;
12576 }
12577 
12578 /** adds coef * expr to nonlinear constraint
12579  *
12580  * @attention This method can only be called in the problem stage.
12581  */
12583  SCIP* scip, /**< SCIP data structure */
12584  SCIP_CONS* cons, /**< nonlinear constraint */
12585  SCIP_EXPR* expr, /**< expression */
12586  SCIP_Real coef /**< coefficient */
12587  )
12588 {
12589  SCIP_CONSHDLR* conshdlr;
12590  SCIP_CONSDATA* consdata;
12591  SCIP_EXPR* exprowned;
12592 
12593  assert(scip != NULL);
12594  assert(cons != NULL);
12595 
12596  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12597  {
12598  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12599  return SCIP_INVALIDCALL;
12600  }
12601 
12602  /* we should have an original constraint */
12603  assert(SCIPconsIsOriginal(cons));
12604 
12605  if( coef == 0.0 )
12606  return SCIP_OKAY;
12607 
12608  conshdlr = SCIPconsGetHdlr(cons);
12609  assert(conshdlr != NULL);
12610  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12611 
12612  consdata = SCIPconsGetData(cons);
12613  assert(consdata != NULL);
12614  assert(consdata->expr != NULL);
12615 
12616  /* we should not have collected additional data for it
12617  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12618  */
12619  assert(consdata->nvarexprs == 0);
12620  assert(consdata->varexprs == NULL);
12621  assert(!consdata->catchedevents);
12622 
12623  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12624  SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12625 
12626  /* append to sum, if consdata->expr is sum and not used anywhere else */
12627  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12628  {
12629  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
12630  }
12631  else
12632  {
12633  /* create new expression = 1 * consdata->expr + coef * var */
12634  SCIP_EXPR* children[2] = { consdata->expr, exprowned };
12635  SCIP_Real coefs[2] = { 1.0, coef };
12636 
12637  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12638 
12639  /* release old root expr */
12640  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12641  }
12642 
12643  SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
12644 
12645  /* not sure we care about any of these flags for original constraints */
12646  consdata->issimplified = FALSE;
12647  consdata->ispropagated = FALSE;
12648 
12649  return SCIP_OKAY;
12650 }
12651 
12652 /** gets absolute violation of nonlinear constraint
12653  *
12654  * This function evaluates the constraints in the given solution.
12655  *
12656  * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
12657  */
12659  SCIP* scip, /**< SCIP data structure */
12660  SCIP_CONS* cons, /**< constraint */
12661  SCIP_SOL* sol, /**< solution to check */
12662  SCIP_Real* viol /**< buffer to store computed violation */
12663  )
12664 {
12665  assert(cons != NULL);
12666  assert(viol != NULL);
12667 
12668  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12669  *viol = getConsAbsViolation(cons);
12670 
12671  return SCIP_OKAY;
12672 }
12673 
12674 /** gets scaled violation of nonlinear constraint
12675  *
12676  * This function evaluates the constraints in the given solution.
12677  *
12678  * The scaling that is applied to the absolute violation of the constraint
12679  * depends on the setting of parameter constraints/nonlinear/violscale.
12680  */
12682  SCIP* scip, /**< SCIP data structure */
12683  SCIP_CONS* cons, /**< constraint */
12684  SCIP_SOL* sol, /**< solution to check */
12685  SCIP_Real* viol /**< buffer to store computed violation */
12686  )
12687 {
12688  assert(cons != NULL);
12689  assert(viol != NULL);
12690 
12691  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12692  SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
12693 
12694  return SCIP_OKAY;
12695 }
12696 
12697 /** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
12699  SCIP* scip, /**< SCIP data structure */
12700  SCIP_CONS* cons, /**< nonlinear constraint */
12701  SCIP_VAR** var, /**< pointer to store the variable */
12702  SCIP_Real* coef /**< pointer to store the coefficient */
12703  )
12704 {
12705  SCIP_CONSDATA* consdata;
12706 
12707  assert(cons != NULL);
12708  assert(var != NULL);
12709  assert(coef != NULL);
12710 
12711  /* check for a linear variable that can be increased or decreased without harming feasibility */
12712  findUnlockedLinearVar(scip, cons);
12713 
12714  consdata = SCIPconsGetData(cons);
12715  assert(consdata != NULL);
12716 
12717  *var = consdata->linvardecr;
12718  *coef = consdata->linvardecrcoef;
12719 }
12720 
12721 /** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
12723  SCIP* scip, /**< SCIP data structure */
12724  SCIP_CONS* cons, /**< nonlinear constraint */
12725  SCIP_VAR** var, /**< pointer to store the variable */
12726  SCIP_Real* coef /**< pointer to store the coefficient */
12727  )
12728 {
12729  SCIP_CONSDATA* consdata;
12730 
12731  assert(cons != NULL);
12732  assert(var != NULL);
12733  assert(coef != NULL);
12734 
12735  /* check for a linear variable that can be increased or decreased without harming feasibility */
12736  findUnlockedLinearVar(scip, cons);
12737 
12738  consdata = SCIPconsGetData(cons);
12739  assert(consdata != NULL);
12740 
12741  *var = consdata->linvarincr;
12742  *coef = consdata->linvarincrcoef;
12743 }
12744 
12745 
12746 /*
12747  * Methods for Expressions in Nonlinear Constraints
12748  */
12749 
12750 /** returns the number of positive rounding locks of an expression */
12752  SCIP_EXPR* expr /**< expression */
12753  )
12754 {
12755  assert(expr != NULL);
12756  assert(SCIPexprGetOwnerData(expr) != NULL);
12757 
12758  return SCIPexprGetOwnerData(expr)->nlockspos;
12759 }
12760 
12761 /** returns the number of negative rounding locks of an expression */
12763  SCIP_EXPR* expr /**< expression */
12764  )
12765 {
12766  assert(expr != NULL);
12767  assert(SCIPexprGetOwnerData(expr) != NULL);
12768 
12769  return SCIPexprGetOwnerData(expr)->nlocksneg;
12770 }
12771 
12772 /** returns the variable used for linearizing a given expression (return value might be NULL)
12773  *
12774  * @note for variable expression it returns the corresponding variable
12775  */
12777  SCIP_EXPR* expr /**< expression */
12778  )
12779 {
12780  SCIP_EXPR_OWNERDATA* ownerdata;
12781 
12782  assert(expr != NULL);
12783 
12784  ownerdata = SCIPexprGetOwnerData(expr);
12785  assert(ownerdata != NULL);
12786 
12787  return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
12788 }
12789 
12790 /** returns the number of enforcements for an expression */
12792  SCIP_EXPR* expr /**< expression */
12793  )
12794 {
12795  assert(expr != NULL);
12796  assert(SCIPexprGetOwnerData(expr) != NULL);
12797 
12798  return SCIPexprGetOwnerData(expr)->nenfos;
12799 }
12800 
12801 /** returns the data for one of the enforcements of an expression */
12803  SCIP_EXPR* expr, /**< expression */
12804  int idx, /**< position of enforcement in enfos array */
12805  SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
12806  SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
12807  SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
12808  SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
12809  SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
12810  SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
12811  )
12812 {
12813  SCIP_EXPR_OWNERDATA* ownerdata;
12814 
12815  assert(expr != NULL);
12816 
12817  ownerdata = SCIPexprGetOwnerData(expr);
12818  assert(ownerdata != NULL);
12819  assert(idx >= 0);
12820  assert(idx < ownerdata->nenfos);
12821  assert(ownerdata->enfos[idx] != NULL);
12822  assert(nlhdlr != NULL);
12823 
12824  *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
12825 
12826  if( nlhdlrexprdata != NULL )
12827  *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
12828 
12829  if( nlhdlrparticipation != NULL )
12830  *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
12831 
12832  if( sepabelowusesactivity != NULL )
12833  *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
12834 
12835  if( sepaaboveusesactivity != NULL )
12836  *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
12837 
12838  if( auxvalue != NULL )
12839  *auxvalue = ownerdata->enfos[idx]->auxvalue;
12840 }
12841 
12842 /** sets the auxiliary value of expression for one of the enforcements of an expression */
12844  SCIP_EXPR* expr, /**< expression */
12845  int idx, /**< position of enforcement in enfos array */
12846  SCIP_Real auxvalue /**< the new value of auxval */
12847  )
12848 {
12849  SCIP_EXPR_OWNERDATA* ownerdata;
12850 
12851  assert(expr != NULL);
12852 
12853  ownerdata = SCIPexprGetOwnerData(expr);
12854  assert(ownerdata != NULL);
12855 
12856  assert(idx >= 0);
12857  assert(idx < ownerdata->nenfos);
12858  assert(ownerdata->enfos[idx] != NULL);
12859 
12860  ownerdata->enfos[idx]->auxvalue = auxvalue;
12861 }
12862 
12863 /** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
12864  *
12865  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12866  */
12868  SCIP_EXPR* expr /**< expression */
12869  )
12870 {
12871  assert(expr != NULL);
12872  assert(SCIPexprGetOwnerData(expr) != NULL);
12873 
12874  return SCIPexprGetOwnerData(expr)->nactivityusesprop;
12875 }
12876 
12877 /** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
12878  *
12879  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12880  */
12882  SCIP_EXPR* expr /**< expression */
12883  )
12884 {
12885  assert(expr != NULL);
12886  assert(SCIPexprGetOwnerData(expr) != NULL);
12887 
12888  return SCIPexprGetOwnerData(expr)->nactivityusessepa;
12889 }
12890 
12891 /** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
12892  *
12893  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12894  */
12895 unsigned int SCIPgetExprNAuxvarUsesNonlinear(
12896  SCIP_EXPR* expr /**< expression */
12897  )
12898 {
12899  assert(expr != NULL);
12900  assert(SCIPexprGetOwnerData(expr) != NULL);
12901 
12902  return SCIPexprGetOwnerData(expr)->nauxvaruses;
12903 }
12904 
12905 /** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
12906  *
12907  * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
12908  * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
12909  * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
12910  * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
12911  * and also increments this count for all variables in the expression.
12912  *
12913  * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
12914  * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
12915  * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
12916  * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
12917  */
12919  SCIP* scip, /**< SCIP data structure */
12920  SCIP_EXPR* expr, /**< expression */
12921  SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
12922  SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
12923  SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
12924  SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
12925  )
12926 {
12927  SCIP_EXPR_OWNERDATA* ownerdata;
12928 
12929  assert(expr != NULL);
12930 
12931  ownerdata = SCIPexprGetOwnerData(expr);
12932  assert(ownerdata != NULL);
12933 
12934  /* do not store auxvar request for variable expressions */
12935  if( useauxvar && SCIPisExprVar(scip, expr) )
12936  useauxvar = FALSE;
12937 
12938  if( ownerdata->nenfos >= 0 &&
12939  ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
12940  (ownerdata->nauxvaruses == 0 && useauxvar)
12941  ) )
12942  {
12943  /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
12944  * we require additional enforcement methods, that is,
12945  * - activity of expr was not used before but will be used now, or
12946  * - auxiliary variable of expr was not required before but will be used now
12947  */
12948  SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
12949  }
12950 
12951  if( useauxvar )
12952  ++ownerdata->nauxvaruses;
12953 
12954  if( useactivityforprop )
12955  ++ownerdata->nactivityusesprop;
12956 
12957  if( useactivityforsepabelow || useactivityforsepaabove )
12958  ++ownerdata->nactivityusessepa;
12959 
12960  /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
12961  * information is used in detectNlhdlr()
12962  */
12963  if( useactivityforsepabelow )
12964  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
12965  if( useactivityforsepaabove )
12966  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
12967 
12968  if( useactivityforprop )
12969  {
12970  /* if activity will be used for propagation, then make sure there is a valid activity
12971  * this way, we can do a reversepropcall after detectNlhdlr
12972  */
12973  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
12974  }
12975 
12976  /* increase the nactivityusedsepa counter for all variables used in the given expression */
12977  if(( useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
12978  {
12979  SCIP_EXPRITER* it;
12980 
12981  /* create and initialize iterator */
12982  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
12984 
12985  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
12986  if( SCIPisExprVar(scip, expr) )
12987  ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
12988 
12989  /* free iterator */
12990  SCIPfreeExpriter(&it);
12991  }
12992 
12993  return SCIP_OKAY;
12994 }
12995 
12996 /** computes absolute violation for auxvar relation in an expression w.r.t. original variables
12997  *
12998  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
12999  * Assume that f(x) is associated with auxiliary variable z.
13000  *
13001  * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
13002  * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
13003  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
13004  *
13005  * If necessary, f is evaluated in the given solution. If that fails (domain error),
13006  * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
13007  */
13009  SCIP* scip, /**< SCIP data structure */
13010  SCIP_EXPR* expr, /**< expression */
13011  SCIP_SOL* sol, /**< solution */
13012  SCIP_Longint soltag, /**< tag of solution */
13013  SCIP_Real* viol, /**< buffer to store computed violation */
13014  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
13015  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
13016  )
13017 {
13018  assert(scip != NULL);
13019  assert(expr != NULL);
13020  assert(viol != NULL);
13021 
13022  /* make sure expression has been evaluated */
13023  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
13024 
13025  /* get violation from internal method */
13026  *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
13027 
13028  return SCIP_OKAY;
13029 }
13030 
13031 /** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
13032  *
13033  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13034  * Assume that f(w) is associated with auxiliary variable z.
13035  *
13036  * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
13037  * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
13038  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
13039  *
13040  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13041  * both `violover` and `violunder` are set to TRUE.
13042  */
13044  SCIP* scip, /**< SCIP data structure */
13045  SCIP_EXPR* expr, /**< expression */
13046  SCIP_Real auxvalue, /**< the value of f(w) */
13047  SCIP_SOL* sol, /**< solution that has been evaluated */
13048  SCIP_Real* viol, /**< buffer to store computed violation */
13049  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13050  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13051  )
13052 {
13053  assert(scip != NULL);
13054  assert(expr != NULL);
13055  assert(viol != NULL);
13056 
13057  /* get violation from internal method */
13058  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13059 
13060  return SCIP_OKAY;
13061 }
13062 
13063 
13064 /** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
13065  *
13066  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13067  * Assume that f(w) is associated with auxiliary variable z.
13068  *
13069  * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
13070  * the absolute violation divided by max(1,|f(w)|).
13071  *
13072  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13073  * both `violover` and `violunder` are set to TRUE.
13074  */
13076  SCIP* scip, /**< SCIP data structure */
13077  SCIP_EXPR* expr, /**< expression */
13078  SCIP_Real auxvalue, /**< the value of f(w) */
13079  SCIP_SOL* sol, /**< solution that has been evaluated */
13080  SCIP_Real* viol, /**< buffer to store computed violation */
13081  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13082  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13083  )
13084 {
13085  assert(scip != NULL);
13086  assert(expr != NULL);
13087  assert(viol != NULL);
13088 
13089  /* get violation from internal method */
13090  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13091 
13092  if( !SCIPisInfinity(scip, *viol) )
13093  {
13094  assert(auxvalue != SCIP_INVALID);
13095  /* TODO maybe we should rather use max(eps,|auxvalue|)? */
13096  *viol /= MAX(1.0, REALABS(auxvalue));
13097  }
13098 
13099  return SCIP_OKAY;
13100 }
13101 
13102 /** returns bounds on the expression
13103  *
13104  * This gives an intersection of bounds from
13105  * - activity calculation (SCIPexprGetActivity()), if valid,
13106  * - auxiliary variable, if present,
13107  * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
13108  *
13109  * @note The returned interval can be empty!
13110  */
13112  SCIP* scip, /**< SCIP data structure */
13113  SCIP_EXPR* expr /**< expression */
13114  )
13115 {
13116  SCIP_EXPR_OWNERDATA* ownerdata;
13117  SCIP_CONSHDLRDATA* conshdlrdata;
13118  SCIP_INTERVAL bounds;
13119 
13120  assert(scip != NULL);
13121  assert(expr != NULL);
13122 
13123  ownerdata = SCIPexprGetOwnerData(expr);
13124  assert(ownerdata != NULL);
13125 
13126  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13127  assert(conshdlrdata != NULL);
13128 
13129  /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
13130 
13131  /* start with propbounds if they belong to current propagation */
13132  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13133  {
13134  bounds = ownerdata->propbounds;
13135  /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
13136  }
13137  else
13139 
13140  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
13141  {
13142  /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
13143  /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
13144  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), bounds);
13145  }
13146 
13147  if( ownerdata->auxvar != NULL )
13148  {
13149  /* apply auxiliary variable bounds to bounds */
13150  SCIP_INTERVAL auxvarbounds;
13151 
13152  auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
13153  /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
13154  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
13155  }
13156 
13157  /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
13158 
13159  return bounds;
13160 }
13161 
13162 /** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
13163  * corresponding (auxiliary) variable (if any)
13164  *
13165  * @attention this function should only be called during domain propagation in cons_nonlinear
13166  */
13168  SCIP* scip, /**< SCIP data structure */
13169  SCIP_EXPR* expr, /**< expression to be tightened */
13170  SCIP_INTERVAL newbounds, /**< new bounds for the expression */
13171  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
13172  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
13173  )
13174 {
13175  SCIP_EXPR_OWNERDATA* ownerdata;
13176  SCIP_CONSHDLRDATA* conshdlrdata;
13177 
13178  assert(scip != NULL);
13179  assert(expr != NULL);
13180  assert(cutoff != NULL);
13181 
13182  ownerdata = SCIPexprGetOwnerData(expr);
13183  assert(ownerdata != NULL);
13184  assert(ownerdata->conshdlr != NULL);
13185 
13186  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13187  assert(conshdlrdata != NULL);
13188 
13189  /* the code below assumes that current activity is valid
13190  * if it turns out that we cannot ensure that, then we should change code
13191  */
13192  assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13194 
13195  *cutoff = FALSE;
13196 
13197 #ifdef DEBUG_PROP
13198  SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
13199  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
13200  SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
13201 #endif
13202 
13203  if( SCIPexprIsIntegral(expr) )
13204  {
13205  /* apply integrality to new bounds
13206  * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
13207  */
13208  if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
13209  newbounds.inf = SCIPceil(scip, newbounds.inf);
13210  if( newbounds.sup < SCIP_INTERVAL_INFINITY )
13211  newbounds.sup = SCIPfloor(scip, newbounds.sup);
13212 #ifdef DEBUG_PROP
13213  SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
13214 #endif
13215  }
13216 
13218  {
13219  SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
13220 
13221  *cutoff = TRUE;
13222  return SCIP_OKAY;
13223  }
13224 
13225  /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
13226  if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
13227  {
13228  SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
13229 
13230  *cutoff = TRUE;
13231  return SCIP_OKAY;
13232  }
13233 
13234  /* tighten newbounds w.r.t. existing expr->propbounds or activity */
13235  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13236  {
13237  /* if already having propbounds in expr, then tighten newbounds by propbounds */
13238  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
13239  }
13240  else
13241  {
13242  /* first time we have propbounds for expr in this propagation rounds:
13243  * intersect with activity (though don't let it become empty if very close intervals)
13244  */
13245  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
13246  }
13247 #ifdef DEBUG_PROP
13248  SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
13249 #endif
13250 
13251  /* check if the new bounds lead to an empty interval */
13253  {
13254  SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
13255 
13256  *cutoff = TRUE;
13257  return SCIP_OKAY;
13258  }
13259 
13260  /* if expr is not constant or variable, then store newbounds in expr->propbounds
13261  * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
13262  * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
13263  */
13264  if( SCIPexprGetNChildren(expr) > 0 )
13265  {
13266  ownerdata->propbounds = newbounds;
13267  ownerdata->propboundstag = conshdlrdata->curpropboundstag;
13268  }
13269 
13270  /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
13271  * propagation or update of auxvar bounds
13272  * TODO? if we first had a considerable tightening and then only get small tightenings under the same
13273  * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
13274  * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
13275  * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
13276  * one or should we not even update propbounds to newbounds if the update is small?
13277  */
13278  if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
13279  {
13280 #ifdef DEBUG_PROP
13281  SCIPdebugMsg(scip, " new bounds [%g,%g] for expr %p not sufficiently tighter than activity -- not adding to propqueue or tightening auxvar\n", newbounds.inf, newbounds.sup, (void*)expr);
13282 #endif
13283  return SCIP_OKAY;
13284  }
13285 
13286  if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
13287  {
13288  /* add expression to propagation queue if not there yet and not var or constant and
13289  * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
13290  */
13291 #ifdef DEBUG_PROP
13292  SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
13293 #endif
13294  SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
13295  ownerdata->inpropqueue = TRUE;
13296  }
13297 
13298  /* update bounds on variable or auxiliary variable */
13299  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
13300 
13301  return SCIP_OKAY;
13302 }
13303 
13304 /** mark constraints that include this expression to be propagated again
13305  *
13306  * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
13307  * a change of variable bounds, e.g., because new information on the expression is available
13308  * that could potentially lead to tighter expression activity values.
13309  *
13310  * Note, that this call marks also constraints for propagation which only share some variable
13311  * with this expression.
13312  */
13314  SCIP* scip, /**< SCIP data structure */
13315  SCIP_EXPR* expr /**< expression to propagate again */
13316  )
13317 {
13318  SCIP_EXPRITER* it;
13319  SCIP_CONSDATA* consdata;
13320  SCIP_EXPR_OWNERDATA* ownerdata;
13321  int c;
13322 
13323  assert(scip != NULL);
13324  assert(expr != NULL);
13325 
13326  ownerdata = SCIPexprGetOwnerData(expr);
13327  assert(ownerdata != NULL);
13328 
13329  SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
13330 
13331  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13333 
13334  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13335  {
13336  if( !SCIPisExprVar(scip, expr) )
13337  continue;
13338 
13339  ownerdata = SCIPexprGetOwnerData(expr);
13340  assert(ownerdata != NULL);
13341 
13342  for( c = 0; c < ownerdata->nconss; ++c )
13343  {
13344  consdata = SCIPconsGetData(ownerdata->conss[c]);
13345  assert(consdata != NULL);
13346  consdata->ispropagated = FALSE;
13347  }
13348  }
13349 
13350  SCIPfreeExpriter(&it);
13351 
13352  return SCIP_OKAY;
13353 }
13354 
13355 /** adds violation-branching score to an expression
13356  *
13357  * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
13358  * The expression must either be a variable expression or have an aux-variable.
13359  * In the latter case, branching on auxiliary variables must have been enabled.
13360  * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
13361  * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
13362  * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
13363  *
13364  * @see SCIPaddExprsViolScoreNonlinear()
13365  */
13367  SCIP* scip, /**< SCIP data structure */
13368  SCIP_EXPR* expr, /**< expression where to add branching score */
13369  SCIP_Real violscore /**< violation score to add to expression */
13370  )
13371 {
13372  SCIP_EXPR_OWNERDATA* ownerdata;
13373  SCIP_CONSHDLRDATA* conshdlrdata;
13374 
13375  assert(scip != NULL);
13376  assert(expr != NULL);
13377  assert(violscore >= 0.0);
13378 
13379  ownerdata = SCIPexprGetOwnerData(expr);
13380  assert(ownerdata != NULL);
13381 
13382  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13383  assert(conshdlrdata != NULL);
13384 
13385  /* if not allowing to branch on auxvars, then expr must be a var-expr */
13386  assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
13387  /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
13388  assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
13389 
13390  /* reset branching score if we are in a different enfo round */
13391  if( ownerdata->violscoretag != conshdlrdata->enforound )
13392  {
13393  ownerdata->violscoresum = violscore;
13394  ownerdata->violscoremax = violscore;
13395  ownerdata->nviolscores = 1;
13396  ownerdata->violscoretag = conshdlrdata->enforound;
13397  return;
13398  }
13399 
13400  ownerdata->violscoresum += violscore;
13401  if( violscore > ownerdata->violscoremax )
13402  ownerdata->violscoremax = violscore;
13403  ++ownerdata->nviolscores;
13404 }
13405 
13406 /** adds violation-branching score to a set of expressions, distributing the score among all the expressions
13407  *
13408  * Each expression must either be a variable expression or have an aux-variable.
13409  * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
13410  * variables present in `exprs`.
13411  */
13413  SCIP* scip, /**< SCIP data structure */
13414  SCIP_EXPR** exprs, /**< expressions where to add branching score */
13415  int nexprs, /**< number of expressions */
13416  SCIP_Real violscore, /**< violation score to add to expression */
13417  SCIP_SOL* sol, /**< current solution */
13418  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
13419  )
13420 {
13421  SCIP_EXPRITER* it;
13422  SCIP_EXPR** varexprs;
13423  SCIP_EXPR* e;
13424  int nvars;
13425  int varssize;
13426  int i;
13427 
13428  assert(exprs != NULL || nexprs == 0);
13429  assert(success != NULL);
13430 
13431  if( nexprs == 0 )
13432  {
13433  *success = FALSE;
13434  return SCIP_OKAY;
13435  }
13436 
13437  /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
13438  if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
13439  {
13440  addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
13441  return SCIP_OKAY;
13442  }
13443 
13444  /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
13445  nvars = 0;
13446  varssize = 5;
13447  SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
13448 
13449  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13451 
13452  for( i = 0; i < nexprs; ++i )
13453  {
13454  for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
13455  {
13456  assert(e != NULL);
13457 
13458  if( SCIPisExprVar(scip, e) )
13459  {
13460  /* add variable expression to vars array */
13461  if( varssize == nvars )
13462  {
13463  varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
13464  SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
13465  }
13466  assert(varssize > nvars);
13467 
13468  varexprs[nvars++] = e;
13469  }
13470  }
13471  }
13472 
13473  SCIPfreeExpriter(&it);
13474 
13475  addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
13476 
13477  SCIPfreeBufferArray(scip, &varexprs);
13478 
13479  return SCIP_OKAY;
13480 }
13481 
13482 /** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
13484  SCIP_EXPR* expr /**< expression */
13485  )
13486 {
13487  SCIP_EXPR_OWNERDATA* ownerdata;
13488  SCIP_CONSHDLRDATA* conshdlrdata;
13489 
13490  assert(expr != NULL);
13491 
13492  ownerdata = SCIPexprGetOwnerData(expr);
13493  assert(ownerdata != NULL);
13494 
13495  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13496  assert(conshdlrdata != NULL);
13497 
13498  if( conshdlrdata->enforound != ownerdata->violscoretag )
13499  return 0.0;
13500 
13501  if( ownerdata->nviolscores == 0 )
13502  return 0.0;
13503 
13504  switch( conshdlrdata->branchscoreagg )
13505  {
13506  case 'a' :
13507  /* average */
13508  return ownerdata->violscoresum / ownerdata->nviolscores;
13509 
13510  case 'm' :
13511  /* maximum */
13512  return ownerdata->violscoremax;
13513 
13514  case 's' :
13515  /* sum */
13516  return ownerdata->violscoresum;
13517 
13518  default:
13519  SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
13520  SCIPABORT();
13521  return SCIP_INVALID;
13522  }
13523 }
13524 
13525 /** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13526  *
13527  * @see SCIPexprGetDerivative()
13528  */
13530  SCIP* scip, /**< SCIP data structure */
13531  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
13532  SCIP_VAR* var /**< variable (needs to be in the expression) */
13533  )
13534 {
13535  SCIP_EXPR_OWNERDATA* ownerdata;
13536  SCIP_CONSHDLRDATA* conshdlrdata;
13537  SCIP_EXPR* varexpr;
13538 
13539  assert(scip != NULL);
13540  assert(expr != NULL);
13541  assert(var != NULL);
13542 
13543  /* return 0.0 for value expression */
13544  if( SCIPisExprValue(scip, expr) )
13545  {
13546  assert(SCIPexprGetDerivative(expr) == 0.0);
13547  return 0.0;
13548  }
13549 
13550  /* check if an error occurred during the last SCIPevalExprGradient() call */
13551  if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
13552  return SCIP_INVALID;
13553 
13554  ownerdata = SCIPexprGetOwnerData(expr);
13555  assert(ownerdata != NULL);
13556 
13557  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13558  assert(conshdlrdata != NULL);
13559 
13560  /* use variable to expressions mapping which is stored in the constraint handler data */
13561  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13562 
13563  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13564  assert(varexpr != NULL);
13565  assert(SCIPisExprVar(scip, varexpr));
13566 
13567  /* use difftag to decide whether the variable belongs to the expression */
13568  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
13569 }
13570 
13571 /** returns the var's coordinate of Hu partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13572  *
13573  * @see SCIPexprGetBardot()
13574  */
13576  SCIP* scip, /**< SCIP data structure */
13577  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
13578  SCIP_VAR* var /**< variable (needs to be in the expression) */
13579  )
13580 {
13581  SCIP_EXPR_OWNERDATA* ownerdata;
13582  SCIP_CONSHDLRDATA* conshdlrdata;
13583  SCIP_EXPR* varexpr;
13584 
13585  assert(scip != NULL);
13586  assert(expr != NULL);
13587  assert(var != NULL);
13588 
13589  /* return 0.0 for value expression */
13590  if( SCIPisExprValue(scip, expr) )
13591  return 0.0;
13592 
13593  /* check if an error occurred during the last SCIPevalExprHessianDir() call */
13594  if( SCIPexprGetBardot(expr) == SCIP_INVALID )
13595  return SCIP_INVALID;
13596 
13597  ownerdata = SCIPexprGetOwnerData(expr);
13598  assert(ownerdata != NULL);
13599 
13600  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13601  assert(conshdlrdata != NULL);
13602 
13603  /* use variable to expressions mapping which is stored in the constraint handler data;
13604  * if this fails it means that we are asking for the var's component of H*u for a var
13605  * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
13606  */
13607  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13608 
13609  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13610  assert(varexpr != NULL);
13611  assert(SCIPisExprVar(scip, varexpr));
13612 
13613  /* use difftag to decide whether the variable belongs to the expression */
13614  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
13615 }
13616 
13617 /** evaluates quadratic term in a solution w.r.t. auxiliary variables
13618  *
13619  * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
13620  */
13622  SCIP* scip, /**< SCIP data structure */
13623  SCIP_EXPR* expr, /**< quadratic expression */
13624  SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
13625  )
13626 {
13627  SCIP_Real auxvalue;
13628  int nlinexprs;
13629  SCIP_Real* lincoefs;
13630  SCIP_EXPR** linexprs;
13631  int nquadexprs;
13632  int nbilinexprs;
13633  int i;
13634 
13635  assert(scip != NULL);
13636  assert(expr != NULL);
13637 
13638  SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
13639 
13640  /* linear terms */
13641  for( i = 0; i < nlinexprs; ++i )
13642  {
13643  assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
13644  auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
13645  }
13646 
13647  /* quadratic terms */
13648  for( i = 0; i < nquadexprs; ++i )
13649  {
13650  SCIP_EXPR* quadexprterm;
13651  SCIP_Real lincoef;
13652  SCIP_Real sqrcoef;
13653  SCIP_Real solval;
13654 
13655  SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
13656 
13657  assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
13658 
13659  solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
13660  auxvalue += (lincoef + sqrcoef * solval) * solval;
13661  }
13662 
13663  /* bilinear terms */
13664  for( i = 0; i < nbilinexprs; ++i )
13665  {
13666  SCIP_EXPR* expr1;
13667  SCIP_EXPR* expr2;
13668  SCIP_Real coef;
13669 
13670  SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
13671 
13672  assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
13673  assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
13674  auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
13675  }
13676 
13677  return auxvalue;
13678 }
13679 
13680 /**@addtogroup PublicNlhdlrInterfaceMethods
13681  * @{
13682  */
13683 
13684 /** creates a nonlinear handler and includes it into the nonlinear constraint handler */
13686  SCIP* scip, /**< SCIP data structure */
13687  SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
13688  const char* name, /**< name of nonlinear handler (must not be NULL) */
13689  const char* desc, /**< description of nonlinear handler (can be NULL) */
13690  int detectpriority, /**< detection priority of nonlinear handler */
13691  int enfopriority, /**< enforcement priority of nonlinear handler */
13692  SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
13693  SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
13694  SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
13695  )
13696 {
13697  SCIP_CONSHDLR* conshdlr;
13698  SCIP_CONSHDLRDATA* conshdlrdata;
13699 
13700  assert(scip != NULL);
13701  assert(nlhdlr != NULL);
13702  assert(detect != NULL);
13703 
13704  /* find myself */
13705  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13706  if( conshdlr == NULL )
13707  {
13708  SCIPerrorMessage("nonlinear constraint handler not found");
13709  return SCIP_PLUGINNOTFOUND;
13710  }
13711 
13712  /* create nlhdlr */
13713  SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
13714 
13715  /* include into constraint handler */
13716  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13717  assert(conshdlrdata != NULL);
13718 
13719  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
13720 
13721  conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
13722  ++conshdlrdata->nnlhdlrs;
13723 
13724  /* sort nonlinear handlers by detection priority, in decreasing order
13725  * will happen in INIT, so only do when called late
13726  */
13727  if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
13728  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
13729 
13730  return SCIP_OKAY;
13731 }
13732 
13733 /** get number of nonlinear handler */
13735  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13736  )
13737 {
13738  SCIP_CONSHDLRDATA* conshdlrdata;
13739 
13740  assert(conshdlr != NULL);
13741 
13742  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13743  assert(conshdlrdata != NULL);
13744 
13745  return conshdlrdata->nnlhdlrs;
13746 }
13747 
13748 /** get nonlinear handlers */
13750  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13751  )
13752 {
13753  SCIP_CONSHDLRDATA* conshdlrdata;
13754 
13755  assert(conshdlr != NULL);
13756 
13757  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13758  assert(conshdlrdata != NULL);
13759 
13760  return conshdlrdata->nlhdlrs;
13761 }
13762 
13763 /** returns a nonlinear handler of a given name (or NULL if not found) */
13765  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13766  const char* name /**< name of nonlinear handler */
13767  )
13768 {
13769  SCIP_CONSHDLRDATA* conshdlrdata;
13770  int h;
13771 
13772  assert(conshdlr != NULL);
13773  assert(name != NULL);
13774 
13775  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13776  assert(conshdlrdata != NULL);
13777 
13778  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
13779  if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
13780  return conshdlrdata->nlhdlrs[h];
13781 
13782  return NULL;
13783 }
13784 
13785 /** gives expression data that a given nonlinear handler stored in an expression
13786  *
13787  * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
13788  */
13790  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
13791  SCIP_EXPR* expr /**< expression */
13792  )
13793 {
13794  SCIP_EXPR_OWNERDATA* ownerdata;
13795  int e;
13796 
13797  assert(nlhdlr != NULL);
13798  assert(expr != NULL);
13799 
13800  ownerdata = SCIPexprGetOwnerData(expr);
13801  assert(ownerdata != NULL);
13802 
13803  for( e = 0; e < ownerdata->nenfos; ++e )
13804  if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
13805  return ownerdata->enfos[e]->nlhdlrexprdata;
13806 
13807  return NULL;
13808 }
13809 
13810 /** @} */
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:17284
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:17245
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:7432
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:17084
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:5111
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:5021
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:17389
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:17073
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:17048
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)