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-2023 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file cons_nonlinear.c
26  * @ingroup DEFPLUGINS_CONS
27  * @brief constraint handler for nonlinear constraints specified by algebraic expressions
28  * @author Ksenia Bestuzheva
29  * @author Benjamin Mueller
30  * @author Felipe Serrano
31  * @author Stefan Vigerske
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #ifdef SCIP_DEBUG
37 #define ENFO_LOGGING
38 #endif
39 
40 /* enable to get log output for enforcement */
41 /* #define ENFO_LOGGING */
42 /* define to get enforcement logging into file */
43 /* #define ENFOLOGFILE "consexpr_enfo.log" */
44 
45 /* define to get more debug output from domain propagation */
46 /* #define DEBUG_PROP */
47 
48 /*lint -e440*/
49 /*lint -e441*/
50 /*lint -e528*/
51 /*lint -e666*/
52 /*lint -e777*/
53 /*lint -e866*/
54 
55 #include <ctype.h>
56 #include "scip/cons_nonlinear.h"
57 #include "scip/nlhdlr.h"
58 #include "scip/expr_var.h"
59 #include "scip/expr_sum.h"
60 #include "scip/expr_value.h"
61 #include "scip/expr_pow.h"
62 #include "scip/nlhdlr_convex.h"
63 #include "scip/cons_linear.h"
64 #include "scip/cons_varbound.h"
65 #include "scip/cons_and.h"
67 #include "scip/heur_subnlp.h"
68 #include "scip/heur_trysol.h"
69 #include "scip/nlpi_ipopt.h" /* for SCIPsolveLinearEquationsIpopt */
70 #include "scip/debug.h"
71 #include "scip/dialog_default.h"
72 
73 
74 /* fundamental constraint handler properties */
75 #define CONSHDLR_NAME "nonlinear"
76 #define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
77 #define CONSHDLR_ENFOPRIORITY -60 /**< priority of the constraint handler for constraint enforcing */
78 #define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
79 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
80  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
81 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
82 
83 /* optional constraint handler properties */
84 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
85 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
86 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
87 
88 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
89 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
90 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
91 
92 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
93 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
94 
95 /* properties of the nonlinear constraint handler statistics table */
96 #define TABLE_NAME_NONLINEAR "cons_nonlinear"
97 #define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
98 #define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
99 #define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
101 /* properties of the nonlinear handler statistics table */
102 #define TABLE_NAME_NLHDLR "nlhdlr"
103 #define TABLE_DESC_NLHDLR "nonlinear handler statistics"
104 #define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
105 #define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
107 #define DIALOG_NAME "nlhdlrs"
108 #define DIALOG_DESC "display nonlinear handlers"
109 #define DIALOG_ISSUBMENU FALSE
111 #define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
112 #define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
113 #define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
114 #define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
116 #define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
118 #define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
120 /** translate from one value of infinity to another
121  *
122  * if val is &ge; infty1, then give infty2, else give val
123  */
124 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
126 /** translates x to 2^x for non-negative integer x */
127 #define POWEROFTWO(x) (0x1u << (x))
129 #ifdef ENFO_LOGGING
130 #define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
131 FILE* enfologfile = NULL;
132 #else
133 #define ENFOLOG(x)
134 #endif
135 
136 /*
137  * Data structures
138  */
139 
140 /** enforcement data of an expression */
141 typedef struct
142 {
143  SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
144  SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
145  SCIP_NLHDLR_METHOD nlhdlrparticipation;/**< methods where nonlinear handler participates */
146  SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
147  SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
148  SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
149  SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
151 
152 /** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
153 struct SCIP_Expr_OwnerData
154 {
155  SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
156 
157  /* locks and monotonicity */
158  int nlockspos; /**< positive locks counter */
159  int nlocksneg; /**< negative locks counter */
160  SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
161  int monotonicitysize; /**< length of monotonicity array */
162 
163  /* propagation (in addition to activity that is stored in expr) */
164  SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
165  unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
166  SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
167 
168  /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
169  EXPRENFO** enfos; /**< enforcements */
170  int nenfos; /**< number of enforcements, or -1 if not initialized */
171  unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
172  unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
173  unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
174  unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
175  SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
176 
177  /* branching */
178  SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
179  SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
180  int nviolscores; /**< number of violation scores stored for this expression */
181  unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
182 
183  /* additional data for variable expressions (TODO move into sub-struct?) */
184  SCIP_CONS** conss; /**< constraints in which this variable appears */
185  int nconss; /**< current number of constraints in conss */
186  int consssize; /**< length of conss array */
187  SCIP_Bool consssorted; /**< is the array of constraints sorted */
188 
189  int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
190 };
191 
192 /** constraint data for nonlinear constraints */
193 struct SCIP_ConsData
194 {
195  /* data that defines the constraint: expression and sides */
196  SCIP_EXPR* expr; /**< expression that represents this constraint */
197  SCIP_Real lhs; /**< left-hand side */
198  SCIP_Real rhs; /**< right-hand side */
199 
200  /* variables */
201  SCIP_EXPR** varexprs; /**< array containing all variable expressions */
202  int nvarexprs; /**< total number of variable expressions */
203  SCIP_Bool catchedevents; /**< do we catch events on variables? */
204 
205  /* constraint violation */
206  SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
207  SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
208  SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
209  SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
210 
211  /* status flags */
212  unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
213  unsigned int issimplified:1; /**< did we simplify the expression tree already? */
214 
215  /* locks */
216  int nlockspos; /**< number of positive locks */
217  int nlocksneg; /**< number of negative locks */
218 
219  /* repair infeasible solutions */
220  SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
221  SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
222  SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
223  SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
224 
225  /* miscellaneous */
226  SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
227  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
228  int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
229 };
230 
231 /** constraint upgrade method */
232 typedef struct
233 {
234  SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
235  int priority; /**< priority of upgrading method */
236  SCIP_Bool active; /**< is upgrading enabled */
238 
239 /** constraint handler data */
240 struct SCIP_ConshdlrData
241 {
242  /* nonlinear handler */
243  SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
244  int nnlhdlrs; /**< number of nonlinear handlers */
245  int nlhdlrssize; /**< size of nlhdlrs array */
246  SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
247  SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
248  SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
249 
250  /* constraint upgrades */
251  CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
252  int consupgradessize; /**< size of consupgrades array */
253  int nconsupgrades; /**< number of constraint upgrade methods */
254 
255  /* other plugins */
256  SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
257  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
258  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
259 
260  /* tags and counters */
261  int auxvarid; /**< unique id for the next auxiliary variable */
262  SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
263  SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
264  SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
265  unsigned int enforound; /**< total number of enforcement calls, including current one */
266  int lastconsindex; /**< last used consindex, plus one */
267 
268  /* activity intervals and domain propagation */
269  SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
270  SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
271  SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
272  SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
273  unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
274 
275  /* parameters */
276  int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
277  SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
278  char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
279  SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
280  SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
281  SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
282  SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
283  SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
284  SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
285  SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
286  int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
287  SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
288  SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
289  SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
290  SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
291  SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
292  SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
293  SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
294  SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
295  SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
296  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 */
297  char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
298  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) */
299  int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
300  SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
301  SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
302  SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
303  SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
304  SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
305  SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
306  SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
307  SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
308  char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
309  char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
310  SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
311  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) */
312  SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
313 
314  /* statistics */
315  SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
316  SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
317  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 */
318  SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
319  SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
320  SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
321  SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
322  SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
323 
324  /* facets of envelops of vertex-polyhedral functions */
325  SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
326  SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
327 
328  /* hashing of bilinear terms */
329  SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
330  SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
331  int nbilinterms; /**< total number of bilinear terms */
332  int bilintermssize; /**< size of bilinterms array */
333  int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
334 
335  /* branching */
336  SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
337  char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
338 
339  /* misc */
340  SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
341  SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
342  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
343 };
344 
345 /** branching candidate with various scores */
346 typedef struct
347 {
348  SCIP_EXPR* expr; /**< expression that holds branching candidate */
349  SCIP_Real auxviol; /**< aux-violation score of candidate */
350  SCIP_Real domain; /**< domain score of candidate */
351  SCIP_Real dual; /**< dual score of candidate */
352  SCIP_Real pscost; /**< pseudo-cost score of candidate */
353  SCIP_Real vartype; /**< variable type score of candidate */
354  SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
356 
357 /*
358  * Local methods
359  */
360 
361 /* forward declaration */
362 static
364  SCIP* scip, /**< SCIP data structure */
365  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
366  SCIP_EXPR* rootexpr, /**< expression */
367  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
368  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
369  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
370  );
371 
372 /** frees auxiliary variables of expression, if any */
373 static
375  SCIP* scip, /**< SCIP data structure */
376  SCIP_EXPR* expr /**< expression which auxvar to free, if any */
377  )
378 {
379  SCIP_EXPR_OWNERDATA* mydata;
380 
381  assert(scip != NULL);
382  assert(expr != NULL);
383 
384  mydata = SCIPexprGetOwnerData(expr);
385  assert(mydata != NULL);
386 
387  if( mydata->auxvar == NULL )
388  return SCIP_OKAY;
389 
390  SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
391 
392  /* remove variable locks
393  * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
394  */
395  SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
396 
397  /* release auxiliary variable */
398  SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
399  assert(mydata->auxvar == NULL);
400 
401  return SCIP_OKAY;
402 }
403 
404 /** frees data used for enforcement of expression, that is, nonlinear handlers
405  *
406  * can also clear indicators whether expr needs enforcement methods, that is,
407  * free an associated auxiliary variable and reset the nactivityuses counts
408  */
409 static
411  SCIP* scip, /**< SCIP data structure */
412  SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
413  SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
414  )
415 {
416  SCIP_EXPR_OWNERDATA* mydata;
417  int e;
418 
419  mydata = SCIPexprGetOwnerData(expr);
420  assert(mydata != NULL);
421 
422  if( freeauxvar )
423  {
424  /* free auxiliary variable */
425  SCIP_CALL( freeAuxVar(scip, expr) );
426  assert(mydata->auxvar == NULL);
427 
428  /* reset count on activity and auxvar usage */
429  mydata->nactivityusesprop = 0;
430  mydata->nactivityusessepa = 0;
431  mydata->nauxvaruses = 0;
432  }
433 
434  /* free data stored by nonlinear handlers */
435  for( e = 0; e < mydata->nenfos; ++e )
436  {
437  SCIP_NLHDLR* nlhdlr;
438 
439  assert(mydata->enfos[e] != NULL);
440 
441  nlhdlr = mydata->enfos[e]->nlhdlr;
442  assert(nlhdlr != NULL);
443 
444  if( mydata->enfos[e]->issepainit )
445  {
446  /* call the separation deinitialization callback of the nonlinear handler */
447  SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
448  mydata->enfos[e]->issepainit = FALSE;
449  }
450 
451  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
452  if( mydata->enfos[e]->nlhdlrexprdata != NULL )
453  {
454  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
455  assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
456  }
457 
458  /* free enfo data */
459  SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
460  }
461 
462  /* free array with enfo data */
463  SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
464 
465  /* we need to look at this expression in detect again */
466  mydata->nenfos = -1;
467 
468  return SCIP_OKAY;
469 }
470 
471 /** callback that frees data that this conshdlr stored in an expression */
472 static
473 SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
474 {
475  assert(scip != NULL);
476  assert(expr != NULL);
477  assert(ownerdata != NULL);
478  assert(*ownerdata != NULL);
479 
480  /* expression should not be locked anymore */
481  assert((*ownerdata)->nlockspos == 0);
482  assert((*ownerdata)->nlocksneg == 0);
483 
484  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
485 
486  /* expression should not be enforced anymore */
487  assert((*ownerdata)->nenfos <= 0);
488  assert((*ownerdata)->auxvar == NULL);
489 
490  if( SCIPisExprVar(scip, expr) )
491  {
492  SCIP_CONSHDLRDATA* conshdlrdata;
493  SCIP_VAR* var;
494 
495  /* there should be no constraints left that still use this variable */
496  assert((*ownerdata)->nconss == 0);
497  /* thus, there should also be no variable event catched (via this exprhdlr) */
498  assert((*ownerdata)->filterpos == -1);
499 
500  SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
501 
502  /* update var2expr hashmap in conshdlrdata */
503  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
504  assert(conshdlrdata != NULL);
505 
506  var = SCIPgetVarExprVar(expr);
507  assert(var != NULL);
508 
509  /* remove var -> expr map from hashmap if present
510  * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
511  * if variable-expression stored for var is different, then also do nothing)
512  */
513  if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
514  {
515  SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
516  }
517  }
518 
519  SCIPfreeBlockMemory(scip, ownerdata);
520 
521  return SCIP_OKAY;
522 }
523 
524 static
525 SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
526 { /*lint --e{715}*/
527  assert(ownerdata != NULL);
528 
529  /* print nl handlers associated to expr */
530  if( ownerdata->nenfos > 0 )
531  {
532  int i;
533  SCIPinfoMessage(scip, file, " {");
534 
535  for( i = 0; i < ownerdata->nenfos; ++i )
536  {
537  SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
538  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
539  SCIPinfoMessage(scip, file, "a");
540  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
541  SCIPinfoMessage(scip, file, "u");
542  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
543  SCIPinfoMessage(scip, file, "o");
544  if( i < ownerdata->nenfos-1 )
545  SCIPinfoMessage(scip, file, ", ");
546  }
547 
548  SCIPinfoMessage(scip, file, "}");
549  }
550 
551  /* print aux var associated to expr */
552  if( ownerdata->auxvar != NULL )
553  {
554  SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
555  }
556  SCIPinfoMessage(scip, file, "\n");
557 
558  return SCIP_OKAY;
559 }
560 
561 /** possibly reevaluates and then returns the activity of the expression
562  *
563  * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
564  */
565 static
566 SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
567 {
568  SCIP_CONSHDLRDATA* conshdlrdata;
569 
570  assert(scip != NULL);
571  assert(expr != NULL);
572  assert(ownerdata != NULL);
573 
574  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
575  assert(conshdlrdata != NULL);
576 
577  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
578  {
579  /* update activity of expression */
580  SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
581 
582  assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
583  }
584 
585  return SCIP_OKAY;
586 }
587 
588 /** callback that creates data that this conshdlr wants to store in an expression */
589 static
590 SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
591 {
592  assert(scip != NULL);
593  assert(expr != NULL);
594  assert(ownerdata != NULL);
595 
596  SCIP_CALL( SCIPallocClearBlockMemory(scip, ownerdata) );
597  (*ownerdata)->nenfos = -1;
598  (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
599 
600  if( SCIPisExprVar(scip, expr) )
601  {
602  SCIP_CONSHDLRDATA* conshdlrdata;
603  SCIP_VAR* var;
604 
605  (*ownerdata)->filterpos = -1;
606 
607  /* add to var2expr hashmap if not having expr for var yet */
608 
609  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
610  assert(conshdlrdata != NULL);
611 
612  var = SCIPgetVarExprVar(expr);
613 
614  if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
615  {
616  /* store the variable expression in the hashmap */
617  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
618  }
619  else
620  {
621  /* if expr was just created, then it shouldn't already be stored as image of var */
622  assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
623  }
624  }
625  else
626  {
627  /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
628  (*ownerdata)->filterpos = -2;
629  }
630 
631  *ownerfree = exprownerFree;
632  *ownerprint = exprownerPrint;
633  *ownerevalactivity = exprownerEvalactivity;
634 
635  return SCIP_OKAY;
636 }
637 
638 /** creates a variable expression or retrieves from hashmap in conshdlr data */
639 static
641  SCIP* scip, /**< SCIP data structure */
642  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
643  SCIP_EXPR** expr, /**< pointer where to store expression */
644  SCIP_VAR* var /**< variable to be stored */
645  )
646 {
647  assert(conshdlr != NULL);
648  assert(expr != NULL);
649  assert(var != NULL);
650 
651  /* get variable expression representing the given variable if there is one already */
652  *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
653 
654  if( *expr == NULL )
655  {
656  /* create a new variable expression; this also captures the expression */
657  SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
658  assert(*expr != NULL);
659  /* exprownerCreate should have added var->expr to var2expr */
660  assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
661  }
662  else
663  {
664  /* only capture already existing expr to get a consistent uses-count */
665  SCIPcaptureExpr(*expr);
666  }
667 
668  return SCIP_OKAY;
669 }
670 
671 /* map var exprs to var-expr from var2expr hashmap */
672 static
673 SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
674 { /*lint --e{715}*/
675  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
676 
677  assert(sourcescip != NULL);
678  assert(targetscip != NULL);
679  assert(sourceexpr != NULL);
680  assert(targetexpr != NULL);
681  assert(*targetexpr == NULL);
682  assert(mapexprdata != NULL);
683 
684  /* do not provide map if not variable */
685  if( !SCIPisExprVar(sourcescip, sourceexpr) )
686  return SCIP_OKAY;
687 
688  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
689 
690  return SCIP_OKAY;
691 }
692 
693 /* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
694 static
695 SCIP_DECL_EXPR_MAPEXPR(mapexprtransvar)
696 { /*lint --e{715}*/
697  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
698  SCIP_VAR* var;
699 
700  assert(sourcescip != NULL);
701  assert(targetscip != NULL);
702  assert(sourceexpr != NULL);
703  assert(targetexpr != NULL);
704  assert(*targetexpr == NULL);
705  assert(mapexprdata != NULL);
706 
707  /* do not provide map if not variable */
708  if( !SCIPisExprVar(sourcescip, sourceexpr) )
709  return SCIP_OKAY;
710 
711  var = SCIPgetVarExprVar(sourceexpr);
712  assert(var != NULL);
713 
714  /* transform variable */
715  SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
716  assert(var != NULL);
717 
718  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
719 
720  return SCIP_OKAY;
721 }
722 
723 /** stores all variable expressions into a given constraint */
724 static
726  SCIP* scip, /**< SCIP data structure */
727  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
728  SCIP_CONSDATA* consdata /**< constraint data */
729  )
730 {
731  SCIP_CONSHDLRDATA* conshdlrdata;
732  int varexprssize;
733  int i;
734 
735  assert(consdata != NULL);
736 
737  /* skip if we have stored the variable expressions already */
738  if( consdata->varexprs != NULL )
739  return SCIP_OKAY;
740 
741  assert(consdata->varexprs == NULL);
742  assert(consdata->nvarexprs == 0);
743 
744  /* get an upper bound on number of variable expressions */
745  if( consdata->issimplified )
746  {
747  /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
748  * so we cannot have more variable expression than the number of active variables
749  */
750  varexprssize = SCIPgetNVars(scip);
751  }
752  else
753  {
754  SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
755  }
756 
757  /* create array to store all variable expressions */
758  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
759 
760  SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
761  assert(varexprssize >= consdata->nvarexprs);
762 
763  /* shrink array if there are less variables in the expression than in the problem */
764  if( varexprssize > consdata->nvarexprs )
765  {
766  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
767  }
768 
769  conshdlrdata = SCIPconshdlrGetData(conshdlr);
770  assert(conshdlrdata != NULL);
771  assert(conshdlrdata->var2expr != NULL);
772 
773  /* ensure that for every variable an entry exists in the var2expr hashmap
774  * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
775  */
776  for( i = 0; i < consdata->nvarexprs; ++i )
777  {
778  if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
779  {
780  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
781  }
782  }
783 
784  return SCIP_OKAY;
785 }
786 
787 /** frees all variable expression stored in storeVarExprs() */
788 static
790  SCIP* scip, /**< SCIP data structure */
791  SCIP_CONSDATA* consdata /**< constraint data */
792  )
793 {
794  int i;
795 
796  assert(consdata != NULL);
797 
798  /* skip if we have stored the variable expressions already*/
799  if( consdata->varexprs == NULL )
800  return SCIP_OKAY;
801 
802  assert(consdata->varexprs != NULL);
803  assert(consdata->nvarexprs >= 0);
804 
805  /* release variable expressions */
806  for( i = 0; i < consdata->nvarexprs; ++i )
807  {
808  assert(consdata->varexprs[i] != NULL);
809  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
810  assert(consdata->varexprs[i] == NULL);
811  }
812 
813  /* free variable expressions */
814  SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
815  consdata->varexprs = NULL;
816  consdata->nvarexprs = 0;
817 
818  return SCIP_OKAY;
819 }
820 
821 /** interval evaluation of variables as used in bound tightening
822  *
823  * Returns slightly relaxed local variable bounds of a variable as interval.
824  * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
825  */
826 static
827 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
828 {
829  SCIP_INTERVAL interval;
830  SCIP_CONSHDLRDATA* conshdlrdata;
831  SCIP_Real lb;
832  SCIP_Real ub;
833 
834  assert(scip != NULL);
835  assert(var != NULL);
836 
837  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
838  assert(conshdlrdata != NULL);
839 
840  if( conshdlrdata->globalbounds )
841  {
842  lb = SCIPvarGetLbGlobal(var);
843  ub = SCIPvarGetUbGlobal(var);
844  }
845  else
846  {
847  lb = SCIPvarGetLbLocal(var);
848  ub = SCIPvarGetUbLocal(var);
849  }
850  assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
851 
852  /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
854  {
855  lb = EPSROUND(lb, 0.0); /*lint !e835*/
856  ub = EPSROUND(ub, 0.0); /*lint !e835*/
857  }
858 
859  /* integer variables should always have integral bounds in SCIP */
860  assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
861  assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
862 
863  switch( conshdlrdata->varboundrelax )
864  {
865  case 'n' : /* no relaxation */
866  break;
867 
868  case 'a' : /* relax by absolute value */
869  {
870  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
871  if( SCIPvarIsIntegral(var) )
872  break;
873 
874  if( !SCIPisInfinity(scip, -lb) )
875  {
876  /* reduce lb by epsilon, or to the next integer value, which ever is larger */
877  SCIP_Real bnd = floor(lb);
878  lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
879  }
880 
881  if( !SCIPisInfinity(scip, ub) )
882  {
883  /* increase ub by epsilon, or to the next integer value, which ever is smaller */
884  SCIP_Real bnd = ceil(ub);
885  ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
886  }
887 
888  break;
889  }
890 
891  case 'b' : /* relax always by absolute value */
892  {
893  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
894  if( SCIPvarIsIntegral(var) )
895  break;
896 
897  if( !SCIPisInfinity(scip, -lb) )
898  lb -= conshdlrdata->varboundrelaxamount;
899 
900  if( !SCIPisInfinity(scip, ub) )
901  ub += conshdlrdata->varboundrelaxamount;
902 
903  break;
904  }
905 
906  case 'r' : /* relax by relative value */
907  {
908  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
909  if( SCIPvarIsIntegral(var) )
910  break;
911 
912  /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
913  * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
914  * further, do not relax beyond next integer value
915  */
916  if( !SCIPisInfinity(scip, -lb) )
917  {
918  SCIP_Real bnd = floor(lb);
919  lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
920  }
921 
922  if( !SCIPisInfinity(scip, ub) )
923  {
924  SCIP_Real bnd = ceil(ub);
925  ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
926  }
927 
928  break;
929  }
930 
931  default :
932  {
933  SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
934  SCIPABORT();
935  break;
936  }
937  }
938 
939  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
942  assert(lb <= ub);
943 
944  SCIPintervalSetBounds(&interval, lb, ub);
945 
946  return interval;
947 }
948 
949 /** compares two nonlinear constraints by its index
950  *
951  * Usable as compare operator in array sort functions.
952  */
953 static
954 SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
955 {
956  SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
957  SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
958 
959  assert(consdata1 != NULL);
960  assert(consdata2 != NULL);
961 
962  return consdata1->consindex - consdata2->consindex;
963 }
964 
965 /** processes variable fixing or bound change event */
966 static
967 SCIP_DECL_EVENTEXEC(processVarEvent)
968 { /*lint --e{715}*/
969  SCIP_EVENTTYPE eventtype;
970  SCIP_EXPR* expr;
971  SCIP_EXPR_OWNERDATA* ownerdata;
972 
973  eventtype = SCIPeventGetType(event);
975 
976  assert(eventdata != NULL);
977  expr = (SCIP_EXPR*) eventdata;
978  assert(SCIPisExprVar(scip, expr));
979 
980  SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
984 
985  ownerdata = SCIPexprGetOwnerData(expr);
986  assert(ownerdata != NULL);
987  /* we only catch varevents for variables in constraints, so there should be constraints */
988  assert(ownerdata->nconss > 0);
989  assert(ownerdata->conss != NULL);
990 
991  /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
992  * - propagation can only find something new if a bound was tightened
993  * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
994  * and we look at global changes (that is, we are not looking at boundchanges in probing)
995  */
997  {
998  SCIP_CONSDATA* consdata;
999  int c;
1000 
1001  for( c = 0; c < ownerdata->nconss; ++c )
1002  {
1003  assert(ownerdata->conss[c] != NULL);
1004  consdata = SCIPconsGetData(ownerdata->conss[c]);
1005 
1006  /* if bound tightening, then mark constraints to be propagated again
1007  * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1008  * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1009  * the locks don't help since they are not available separately for each constraint
1010  */
1011  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1012  {
1013  consdata->ispropagated = FALSE;
1014  SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1015  }
1016 
1017  /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1018  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !SCIPinProbing(scip) )
1019  {
1020  consdata->issimplified = FALSE;
1021  SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1022  }
1023  }
1024  }
1025 
1026  /* update curboundstag, lastboundrelax, and expr activity */
1027  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1028  {
1029  SCIP_CONSHDLRDATA* conshdlrdata;
1030  SCIP_INTERVAL activity;
1031 
1032  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1033  assert(conshdlrdata != NULL);
1034 
1035  /* increase tag on bounds */
1036  ++conshdlrdata->curboundstag;
1037  assert(conshdlrdata->curboundstag > 0);
1038 
1039  /* remember also if we relaxed bounds now */
1040  if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1041  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1042 
1043  /* update the activity of the var-expr here immediately
1044  * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1045  */
1046  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1047  /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1048 #ifdef DEBUG_PROP
1049  SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1050 #endif
1051  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1052  }
1053 
1054  return SCIP_OKAY;
1055 }
1056 
1057 /** registers event handler to catch variable events on variable
1058  *
1059  * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1060  * When an event occurs, all stored constraints are notified.
1061  */
1062 static
1064  SCIP* scip, /**< SCIP data structure */
1065  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1066  SCIP_EXPR* expr, /**< variable expression */
1067  SCIP_CONS* cons /**< nonlinear constraint */
1068  )
1069 {
1070  SCIP_EXPR_OWNERDATA* ownerdata;
1071 
1072  assert(eventhdlr != NULL);
1073  assert(expr != NULL);
1074  assert(SCIPisExprVar(scip, expr));
1075  assert(cons != NULL);
1076 
1077  ownerdata = SCIPexprGetOwnerData(expr);
1078  assert(ownerdata != NULL);
1079 
1080 #ifndef NDEBUG
1081  /* assert that constraint does not double-catch variable */
1082  {
1083  int i;
1084  for( i = 0; i < ownerdata->nconss; ++i )
1085  assert(ownerdata->conss[i] != cons);
1086  }
1087 #endif
1088 
1089  /* append cons to ownerdata->conss */
1090  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1091  ownerdata->conss[ownerdata->nconss++] = cons;
1092  /* we're not capturing the constraint here to avoid circular references */
1093 
1094  /* updated sorted flag */
1095  if( ownerdata->nconss <= 1 )
1096  ownerdata->consssorted = TRUE;
1097  else if( ownerdata->consssorted )
1098  ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1099 
1100  /* catch variable events, if not done so yet (first constraint) */
1101  if( ownerdata->filterpos < 0 )
1102  {
1103  SCIP_EVENTTYPE eventtype;
1104 
1105  assert(ownerdata->nconss == 1);
1106 
1108 
1109  SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1110  assert(ownerdata->filterpos >= 0);
1111  }
1112 
1113  return SCIP_OKAY;
1114 }
1115 
1116 /** catch variable events */
1117 static
1119  SCIP* scip, /**< SCIP data structure */
1120  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1121  SCIP_CONS* cons /**< constraint for which to catch bound change events */
1122  )
1123 {
1124  SCIP_CONSHDLRDATA* conshdlrdata;
1125  SCIP_CONSDATA* consdata;
1126  SCIP_EXPR* expr;
1127  int i;
1128 
1129  assert(eventhdlr != NULL);
1130  assert(cons != NULL);
1131 
1132  consdata = SCIPconsGetData(cons);
1133  assert(consdata != NULL);
1134  assert(consdata->varexprs != NULL);
1135  assert(consdata->nvarexprs >= 0);
1136 
1137  /* check if we have catched variable events already */
1138  if( consdata->catchedevents )
1139  return SCIP_OKAY;
1140 
1141  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1142  assert(conshdlrdata != NULL);
1143 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1144  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1145 #endif
1146 
1147  SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1148 
1149  for( i = 0; i < consdata->nvarexprs; ++i )
1150  {
1151  expr = consdata->varexprs[i];
1152 
1153  assert(expr != NULL);
1154  assert(SCIPisExprVar(scip, expr));
1155 
1156  SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1157 
1158  /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1159  * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1160  */
1161  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1162  {
1163  SCIP_INTERVAL activity;
1164  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1165  /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1166  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1167 #ifdef DEBUG_PROP
1168  SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1169 #endif
1170  }
1171  }
1172 
1173  consdata->catchedevents = TRUE;
1174 
1175  return SCIP_OKAY;
1176 }
1177 
1178 /** unregisters event handler to catch variable events on variable
1179  *
1180  * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1181  * If this was the last constraint, then the event handler is unregistered for this variable.
1182  */
1183 static
1185  SCIP* scip, /**< SCIP data structure */
1186  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1187  SCIP_EXPR* expr, /**< variable expression */
1188  SCIP_CONS* cons /**< expr constraint */
1189  )
1190 {
1191  SCIP_EXPR_OWNERDATA* ownerdata;
1192  int pos;
1193 
1194  assert(eventhdlr != NULL);
1195  assert(expr != NULL);
1196  assert(SCIPisExprVar(scip, expr));
1197  assert(cons != NULL);
1198 
1199  ownerdata = SCIPexprGetOwnerData(expr);
1200  assert(ownerdata != NULL);
1201  assert(ownerdata->nconss > 0);
1202 
1203  if( ownerdata->conss[ownerdata->nconss-1] == cons )
1204  {
1205  pos = ownerdata->nconss-1;
1206  }
1207  else
1208  {
1209  if( !ownerdata->consssorted )
1210  {
1211  SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1212  ownerdata->consssorted = TRUE;
1213  }
1214 
1215  if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1216  {
1217  SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1218  return SCIP_ERROR;
1219  }
1220  assert(pos >= 0 && pos < ownerdata->nconss);
1221  }
1222  assert(ownerdata->conss[pos] == cons);
1223 
1224  /* move last constraint into position of removed constraint */
1225  if( pos < ownerdata->nconss-1 )
1226  {
1227  ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1228  ownerdata->consssorted = FALSE;
1229  }
1230  --ownerdata->nconss;
1231 
1232  /* drop variable events if that was the last constraint */
1233  if( ownerdata->nconss == 0 )
1234  {
1235  SCIP_EVENTTYPE eventtype;
1236 
1237  assert(ownerdata->filterpos >= 0);
1238 
1240 
1241  SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1242  ownerdata->filterpos = -1;
1243  }
1244 
1245  return SCIP_OKAY;
1246 }
1247 
1248 /** drop variable events */
1249 static
1251  SCIP* scip, /**< SCIP data structure */
1252  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1253  SCIP_CONS* cons /**< constraint for which to drop bound change events */
1254  )
1255 {
1256  SCIP_CONSDATA* consdata;
1257  int i;
1258 
1259  assert(eventhdlr != NULL);
1260  assert(cons != NULL);
1261 
1262  consdata = SCIPconsGetData(cons);
1263  assert(consdata != NULL);
1264 
1265  /* check if we have catched variable events already */
1266  if( !consdata->catchedevents )
1267  return SCIP_OKAY;
1268 
1269  assert(consdata->varexprs != NULL);
1270  assert(consdata->nvarexprs >= 0);
1271 
1272  SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1273 
1274  for( i = consdata->nvarexprs - 1; i >= 0; --i )
1275  {
1276  assert(consdata->varexprs[i] != NULL);
1277 
1278  SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1279  }
1280 
1281  consdata->catchedevents = FALSE;
1282 
1283  return SCIP_OKAY;
1284 }
1285 
1286 /** creates and captures a nonlinear constraint
1287  *
1288  * @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
1289  */
1290 static
1292  SCIP* scip, /**< SCIP data structure */
1293  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1294  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1295  const char* name, /**< name of constraint */
1296  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1297  SCIP_Real lhs, /**< left hand side of constraint */
1298  SCIP_Real rhs, /**< right hand side of constraint */
1299  SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1300  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1301  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1302  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1303  * Usually set to TRUE. */
1304  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1305  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1306  SCIP_Bool check, /**< should the constraint be checked for feasibility?
1307  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1308  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1309  * Usually set to TRUE. */
1310  SCIP_Bool local, /**< is constraint only valid locally?
1311  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1312  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1313  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1314  * adds coefficients to this constraint. */
1315  SCIP_Bool dynamic, /**< is constraint subject to aging?
1316  * Usually set to FALSE. Set to TRUE for own cuts which
1317  * are separated as constraints. */
1318  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1319  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1320  )
1321 {
1322  SCIP_CONSHDLRDATA* conshdlrdata;
1323  SCIP_CONSDATA* consdata;
1324 
1325  assert(conshdlr != NULL);
1326  assert(expr != NULL);
1327 
1328  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1329  assert(conshdlrdata != NULL);
1330 
1331  if( local && SCIPgetDepth(scip) != 0 )
1332  {
1333  SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1334  return SCIP_INVALIDCALL;
1335  }
1336 
1337  /* TODO we should allow for non-initial nonlinear constraints */
1338  if( !initial )
1339  {
1340  SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1341  return SCIP_INVALIDCALL;
1342  }
1343 
1344  /* create constraint data */
1345  SCIP_CALL( SCIPallocClearBlockMemory(scip, &consdata) );
1346 
1347  if( copyexpr )
1348  {
1349  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1350  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1351  }
1352  else
1353  {
1354  consdata->expr = expr;
1355  SCIPcaptureExpr(consdata->expr);
1356  }
1357  consdata->lhs = lhs;
1358  consdata->rhs = rhs;
1359  consdata->consindex = conshdlrdata->lastconsindex++;
1360  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1361 
1362  /* create constraint */
1363  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1364  local, modifiable, dynamic, removable, FALSE) );
1365 
1366  return SCIP_OKAY;
1367 }
1368 
1369 /** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1370  *
1371  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1372  * Assume that f(x) is associated with auxiliary variable z.
1373  *
1374  * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1375  * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1376  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1377  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1378  *
1379  * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1380  */
1381 static
1383  SCIP* scip, /**< SCIP data structure */
1384  SCIP_EXPR* expr, /**< expression */
1385  SCIP_SOL* sol, /**< solution that has been evaluated */
1386  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1387  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1388  )
1389 {
1390  SCIP_EXPR_OWNERDATA* ownerdata;
1391  SCIP_Real auxvarvalue;
1392 
1393  assert(expr != NULL);
1394 
1395  ownerdata = SCIPexprGetOwnerData(expr);
1396  assert(ownerdata != NULL);
1397  assert(ownerdata->auxvar != NULL);
1398 
1399  if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1400  {
1401  if( violunder != NULL )
1402  *violunder = TRUE;
1403  if( violover != NULL )
1404  *violover = TRUE;
1405  return SCIPinfinity(scip);
1406  }
1407 
1408  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1409 
1410  if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1411  {
1412  if( violunder != NULL )
1413  *violunder = FALSE;
1414  if( violover != NULL )
1415  *violover = TRUE;
1416  return auxvarvalue - SCIPexprGetEvalValue(expr);
1417  }
1418 
1419  if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1420  {
1421  if( violunder != NULL )
1422  *violunder = TRUE;
1423  if( violover != NULL )
1424  *violover = FALSE;
1425  return SCIPexprGetEvalValue(expr) - auxvarvalue;
1426  }
1427 
1428  if( violunder != NULL )
1429  *violunder = FALSE;
1430  if( violover != NULL )
1431  *violover = FALSE;
1432  return 0.0;
1433 }
1434 
1435 /** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1436  *
1437  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1438  * Assume that f(w) is associated with auxiliary variable z.
1439  *
1440  * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1441  * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1442  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1443  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1444  *
1445  * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1446  */
1447 static
1449  SCIP* scip, /**< SCIP data structure */
1450  SCIP_EXPR* expr, /**< expression */
1451  SCIP_Real auxvalue, /**< value of f(w) */
1452  SCIP_SOL* sol, /**< solution that has been evaluated */
1453  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1454  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1455  )
1456 {
1457  SCIP_EXPR_OWNERDATA* ownerdata;
1458  SCIP_Real auxvarvalue;
1459 
1460  assert(expr != NULL);
1461 
1462  ownerdata = SCIPexprGetOwnerData(expr);
1463  assert(ownerdata != NULL);
1464  assert(ownerdata->auxvar != NULL);
1465 
1466  if( auxvalue == SCIP_INVALID )
1467  {
1468  if( violunder != NULL )
1469  *violunder = TRUE;
1470  if( violover != NULL )
1471  *violover = TRUE;
1472  return SCIPinfinity(scip);
1473  }
1474 
1475  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1476 
1477  if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1478  {
1479  if( violunder != NULL )
1480  *violunder = FALSE;
1481  if( violover != NULL )
1482  *violover = TRUE;
1483  return auxvarvalue - auxvalue;
1484  }
1485 
1486  if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1487  {
1488  if( violunder != NULL )
1489  *violunder = TRUE;
1490  if( violover != NULL )
1491  *violover = FALSE;
1492  return auxvalue - auxvarvalue;
1493  }
1494 
1495  if( violunder != NULL )
1496  *violunder = FALSE;
1497  if( violover != NULL )
1498  *violover = FALSE;
1499 
1500  return 0.0;
1501 }
1502 
1503 /** computes violation of a constraint */
1504 static
1506  SCIP* scip, /**< SCIP data structure */
1507  SCIP_CONS* cons, /**< constraint */
1508  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1509  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1510  )
1511 {
1512  SCIP_CONSDATA* consdata;
1513  SCIP_Real activity;
1514 
1515  assert(scip != NULL);
1516  assert(cons != NULL);
1517 
1518  consdata = SCIPconsGetData(cons);
1519  assert(consdata != NULL);
1520 
1521  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1522  activity = SCIPexprGetEvalValue(consdata->expr);
1523 
1524  /* consider constraint as violated if it is undefined in the current point */
1525  if( activity == SCIP_INVALID )
1526  {
1527  consdata->lhsviol = SCIPinfinity(scip);
1528  consdata->rhsviol = SCIPinfinity(scip);
1529  return SCIP_OKAY;
1530  }
1531 
1532  /* compute violations */
1533  consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1534  consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1535 
1536  return SCIP_OKAY;
1537 }
1538 
1539 /** returns absolute violation of a constraint
1540  *
1541  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1542  */
1543 static
1545  SCIP_CONS* cons /**< constraint */
1546  )
1547 {
1548  SCIP_CONSDATA* consdata;
1549 
1550  assert(cons != NULL);
1551 
1552  consdata = SCIPconsGetData(cons);
1553  assert(consdata != NULL);
1554 
1555  return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1556 }
1557 
1558 /** computes relative violation of a constraint
1559  *
1560  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1561  */
1562 static
1564  SCIP* scip, /**< SCIP data structure */
1565  SCIP_CONS* cons, /**< constraint */
1566  SCIP_Real* viol, /**< buffer to store violation */
1567  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1568  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1569  )
1570 {
1571  SCIP_CONSHDLR* conshdlr;
1572  SCIP_CONSHDLRDATA* conshdlrdata;
1573  SCIP_CONSDATA* consdata;
1574  SCIP_Real scale;
1575 
1576  assert(cons != NULL);
1577  assert(viol != NULL);
1578 
1579  conshdlr = SCIPconsGetHdlr(cons);
1580  assert(conshdlr != NULL);
1581 
1582  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1583  assert(conshdlrdata != NULL);
1584 
1585  *viol = getConsAbsViolation(cons);
1586 
1587  if( conshdlrdata->violscale == 'n' )
1588  return SCIP_OKAY;
1589 
1590  if( SCIPisInfinity(scip, *viol) )
1591  return SCIP_OKAY;
1592 
1593  consdata = SCIPconsGetData(cons);
1594  assert(consdata != NULL);
1595 
1596  if( conshdlrdata->violscale == 'a' )
1597  {
1598  scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1599 
1600  /* consider value of side that is violated for scaling, too */
1601  if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1602  {
1603  assert(!SCIPisInfinity(scip, -consdata->lhs));
1604  scale = REALABS(consdata->lhs);
1605  }
1606  else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1607  {
1608  assert(!SCIPisInfinity(scip, consdata->rhs));
1609  scale = REALABS(consdata->rhs);
1610  }
1611 
1612  *viol /= scale;
1613  return SCIP_OKAY;
1614  }
1615 
1616  /* if not 'n' or 'a', then it has to be 'g' at the moment */
1617  assert(conshdlrdata->violscale == 'g');
1618  if( soltag == 0L || consdata->gradnormsoltag != soltag )
1619  {
1620  /* we need the varexprs to conveniently access the gradient */
1621  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1622 
1623  /* update cached value of norm of gradient */
1624  consdata->gradnorm = 0.0;
1625 
1626  /* compute gradient */
1627  SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1628 
1629  /* gradient evaluation error -> no scaling */
1630  if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1631  {
1632  int i;
1633  for( i = 0; i < consdata->nvarexprs; ++i )
1634  {
1635  SCIP_Real deriv;
1636 
1637  assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1638  deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1639  if( deriv == SCIP_INVALID )
1640  {
1641  /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1642  consdata->gradnorm = 0.0;
1643  break;
1644  }
1645 
1646  consdata->gradnorm += deriv*deriv;
1647  }
1648  }
1649  consdata->gradnorm = sqrt(consdata->gradnorm);
1650  consdata->gradnormsoltag = soltag;
1651  }
1652 
1653  *viol /= MAX(1.0, consdata->gradnorm);
1654 
1655  return SCIP_OKAY;
1656 }
1657 
1658 /** returns whether constraint is currently violated
1659  *
1660  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1661  */
1662 static
1664  SCIP* scip, /**< SCIP data structure */
1665  SCIP_CONS* cons /**< constraint */
1666  )
1667 {
1668  return getConsAbsViolation(cons) > SCIPfeastol(scip);
1669 }
1670 
1671 /** checks for a linear variable that can be increased or decreased without harming feasibility */
1672 static
1674  SCIP* scip, /**< SCIP data structure */
1675  SCIP_CONS* cons /**< constraint */
1676  )
1677 {
1678  SCIP_CONSDATA* consdata;
1679  int poslock;
1680  int neglock;
1681  int i;
1682 
1683  assert(cons != NULL);
1684 
1685  consdata = SCIPconsGetData(cons);
1686  assert(consdata != NULL);
1687 
1688  consdata->linvarincr = NULL;
1689  consdata->linvardecr = NULL;
1690  consdata->linvarincrcoef = 0.0;
1691  consdata->linvardecrcoef = 0.0;
1692 
1693  /* root expression is not a sum -> no unlocked linear variable available */
1694  if( !SCIPisExprSum(scip, consdata->expr) )
1695  return;
1696 
1697  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1698  {
1699  SCIP_EXPR* child;
1700 
1701  child = SCIPexprGetChildren(consdata->expr)[i];
1702  assert(child != NULL);
1703 
1704  /* check whether the child is a variable expression */
1705  if( SCIPisExprVar(scip, child) )
1706  {
1707  SCIP_VAR* var = SCIPgetVarExprVar(child);
1708  SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1709 
1710  if( coef > 0.0 )
1711  {
1712  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1713  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1714  }
1715  else
1716  {
1717  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1718  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1719  }
1721 
1722  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1723  {
1724  /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1725  * if we have already one candidate, then take the one where the loss in the objective function is less
1726  */
1727  if( (consdata->linvardecr == NULL) ||
1728  (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1729  {
1730  consdata->linvardecr = var;
1731  consdata->linvardecrcoef = coef;
1732  }
1733  }
1734 
1735  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1736  {
1737  /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1738  * if we have already one candidate, then take the one where the loss in the objective function is less
1739  */
1740  if( (consdata->linvarincr == NULL) ||
1741  (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1742  {
1743  consdata->linvarincr = var;
1744  consdata->linvarincrcoef = coef;
1745  }
1746  }
1747  }
1748  }
1749 
1750  assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1751  assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1752 
1753  if( consdata->linvarincr != NULL )
1754  {
1755  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1756  }
1757  if( consdata->linvardecr != NULL )
1758  {
1759  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1760  }
1761 }
1762 
1763 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1764  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1765  *
1766  * The method assumes that this is always possible and that not all constraints are feasible already.
1767  */
1768 static
1770  SCIP* scip, /**< SCIP data structure */
1771  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1772  SCIP_CONS** conss, /**< constraints to process */
1773  int nconss, /**< number of constraints */
1774  SCIP_SOL* sol, /**< solution to process */
1775  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1776  )
1777 {
1778  SCIP_CONSHDLRDATA* conshdlrdata;
1779  SCIP_SOL* newsol;
1780  int c;
1781 
1782  assert(scip != NULL);
1783  assert(conshdlr != NULL);
1784  assert(conss != NULL || nconss == 0);
1785  assert(success != NULL);
1786 
1787  *success = FALSE;
1788 
1789  /* don't propose new solutions if not in presolve or solving */
1791  return SCIP_OKAY;
1792 
1793  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1794  assert(conshdlrdata != NULL);
1795 
1796  if( sol != NULL )
1797  {
1798  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1799  }
1800  else
1801  {
1802  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1803  }
1804  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1805  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1806  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1807 
1808  for( c = 0; c < nconss; ++c )
1809  {
1810  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1811  SCIP_Real viol = 0.0;
1812  SCIP_Real delta;
1813  SCIP_Real gap;
1814 
1815  assert(consdata != NULL);
1816 
1817  /* get absolute violation and sign */
1818  if( consdata->lhsviol > SCIPfeastol(scip) )
1819  viol = consdata->lhsviol; /* lhs - activity */
1820  else if( consdata->rhsviol > SCIPfeastol(scip) )
1821  viol = -consdata->rhsviol; /* rhs - activity */
1822  else
1823  continue; /* constraint is satisfied */
1824 
1825  if( consdata->linvarincr != NULL &&
1826  ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1827  {
1828  SCIP_VAR* var = consdata->linvarincr;
1829 
1830  /* compute how much we would like to increase var */
1831  delta = viol / consdata->linvarincrcoef;
1832  assert(delta > 0.0);
1833 
1834  /* if var has an upper bound, may need to reduce delta */
1835  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1836  {
1837  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1838  delta = MIN(MAX(0.0, gap), delta);
1839  }
1840  if( SCIPisPositive(scip, delta) )
1841  {
1842  /* if variable is integral, round delta up so that it will still have an integer value */
1843  if( SCIPvarIsIntegral(var) )
1844  delta = SCIPceil(scip, delta);
1845 
1846  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1847  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1848  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1849 
1850  /* adjust constraint violation, if satisfied go on to next constraint */
1851  viol -= consdata->linvarincrcoef * delta;
1852  if( SCIPisZero(scip, viol) )
1853  continue;
1854  }
1855  }
1856 
1857  assert(viol != 0.0);
1858  if( consdata->linvardecr != NULL &&
1859  ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1860  {
1861  SCIP_VAR* var = consdata->linvardecr;
1862 
1863  /* compute how much we would like to decrease var */
1864  delta = viol / consdata->linvardecrcoef;
1865  assert(delta < 0.0);
1866 
1867  /* if var has a lower bound, may need to reduce delta */
1868  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
1869  {
1870  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1871  delta = MAX(MIN(0.0, gap), delta);
1872  }
1873  if( SCIPisNegative(scip, delta) )
1874  {
1875  /* if variable is integral, round delta down so that it will still have an integer value */
1876  if( SCIPvarIsIntegral(var) )
1877  delta = SCIPfloor(scip, delta);
1878  SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1879  /*lint --e{613} */
1880  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1881  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1882 
1883  /* adjust constraint violation, if satisfied go on to next constraint */
1884  viol -= consdata->linvardecrcoef * delta;
1885  if( SCIPisZero(scip, viol) )
1886  continue;
1887  }
1888  }
1889 
1890  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1891  break;
1892  }
1893 
1894  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1895  * then pass it to the trysol heuristic
1896  */
1897  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1898  {
1899  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1900 
1901  assert(conshdlrdata->trysolheur != NULL);
1902  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1903 
1904  *success = TRUE;
1905  }
1906 
1907  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1908 
1909  return SCIP_OKAY;
1910 }
1911 
1912 /** adds globally valid tight estimators in a given solution as cut to cutpool
1913  *
1914  * Called by addTightEstimatorCuts() for a specific expression, nlhdlr, and estimate-direction (over or under).
1915  */
1916 static
1918  SCIP* scip, /**< SCIP data structure */
1919  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1920  SCIP_CONS* cons, /**< constraint */
1921  SCIP_EXPR* expr, /**< expression */
1922  EXPRENFO* exprenfo, /**< expression enfo data, e.g., nlhdlr to use */
1923  SCIP_SOL* sol, /**< reference point where to estimate */
1924  SCIP_Bool overestimate, /**< whether to overestimate */
1925  SCIP_PTRARRAY* rowpreps /**< array for rowpreps */
1926  )
1927 {
1928  SCIP_Bool estimatesuccess = FALSE;
1929  SCIP_Bool branchscoresuccess = FALSE;
1930  int minidx;
1931  int maxidx;
1932  int r;
1933 
1934  assert(scip != NULL);
1935  assert(expr != NULL);
1936  assert(exprenfo != NULL);
1937  assert(rowpreps != NULL);
1938 
1939  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %sestimate using nlhdlr <%s> for expr %p (%s)\n",
1940  overestimate ? "over" : "under", SCIPnlhdlrGetName(exprenfo->nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))); )
1941 
1942  SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, exprenfo->nlhdlr, expr, exprenfo->nlhdlrexprdata, sol,
1943  exprenfo->auxvalue, overestimate, overestimate ? SCIPinfinity(scip) : -SCIPinfinity(scip), FALSE, rowpreps, &estimatesuccess, &branchscoresuccess) );
1944 
1945  minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
1946  maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
1947  assert(estimatesuccess == (minidx <= maxidx));
1948 
1949  if( !estimatesuccess )
1950  {
1951  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n", SCIPnlhdlrGetName(exprenfo->nlhdlr)); )
1952  return SCIP_OKAY;
1953  }
1954 
1955  for( r = minidx; r <= maxidx; ++r )
1956  {
1957  SCIP_ROWPREP* rowprep;
1958  SCIP_ROW* row;
1959  SCIP_Real estimateval;
1960  int i;
1961 
1962  rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
1963  assert(rowprep != NULL);
1964  assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
1965 
1966  /* if estimators is only local valid, then skip */
1967  if( SCIProwprepIsLocal(rowprep) )
1968  {
1969  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip local estimator\n"); )
1970  SCIPfreeRowprep(scip, &rowprep);
1971  continue;
1972  }
1973 
1974  /* compute value of estimator */
1975  estimateval = -SCIProwprepGetSide(rowprep);
1976  for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
1977  estimateval += SCIProwprepGetCoefs(rowprep)[i] * SCIPgetSolVal(scip, sol, SCIProwprepGetVars(rowprep)[i]);
1978 
1979  /* if estimator value is not tight (or even "more than tight", e.g., when estimating in integer vars), then skip */
1980  if( (overestimate && !SCIPisFeasLE(scip, estimateval, SCIPexprGetEvalValue(expr))) ||
1981  (!overestimate && !SCIPisFeasGE(scip, estimateval, SCIPexprGetEvalValue(expr))) )
1982  {
1983  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip non-tight estimator with value %g, expr value %g\n", estimateval, SCIPexprGetEvalValue(expr)); )
1984  SCIPfreeRowprep(scip, &rowprep);
1985  continue;
1986  }
1987 
1988  /* complete estimator to cut and clean it up */
1989  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
1990  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPinfinity(scip), &estimatesuccess) );
1991 
1992  /* if cleanup failed or rowprep is local now, then skip */
1993  if( !estimatesuccess || SCIProwprepIsLocal(rowprep) )
1994  {
1995  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip after cleanup failed or made estimator locally valid\n"); )
1996  SCIPfreeRowprep(scip, &rowprep);
1997  continue;
1998  }
1999 
2000  /* generate row and add to cutpool */
2001  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
2002 
2003  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
2004  SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
2005 
2006  SCIP_CALL( SCIPaddPoolCut(scip, row) );
2007  /* SCIPnlhdlrIncrementNSeparated(nlhdlr); */
2008 
2009  SCIP_CALL( SCIPreleaseRow(scip, &row) );
2010  SCIPfreeRowprep(scip, &rowprep);
2011  }
2012 
2013  SCIP_CALL( SCIPclearPtrarray(scip, rowpreps) );
2014 
2015  return SCIP_OKAY;
2016 }
2017 
2018 /** adds globally valid tight estimators in a given solution as cuts to cutpool
2019  *
2020  * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
2021  * For convex constraints, we would achieve this by linearizing.
2022  * To avoid checking explicitly for convexity, we compute estimators via any nlhdlr that didn't say it would
2023  * use bound information and check whether the estimator is tight.
2024  *
2025  * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
2026  * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
2027  */
2028 static
2030  SCIP* scip, /**< SCIP data structure */
2031  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2032  SCIP_CONS** conss, /**< constraints */
2033  int nconss, /**< number of constraints */
2034  SCIP_SOL* sol /**< reference point where to estimate */
2035  )
2036 {
2037  SCIP_CONSDATA* consdata;
2038  SCIP_Longint soltag;
2039  SCIP_EXPRITER* it;
2040  SCIP_EXPR* expr;
2041  SCIP_PTRARRAY* rowpreps;
2042  int c, e;
2043 
2044  assert(scip != NULL);
2045  assert(conshdlr != NULL);
2046  assert(conss != NULL || nconss == 0);
2047 
2048  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "add tight estimators in new solution from <%s> to cutpool\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
2049 
2050  /* TODO probably we just evaluated all expressions when checking the sol before it was added
2051  * would be nice to recognize this and skip reevaluating
2052  */
2053  soltag = SCIPgetExprNewSoltag(scip);
2054 
2055  SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
2056 
2057  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2060 
2061  for( c = 0; c < nconss; ++c )
2062  {
2063  /* skip constraints that are not enabled or deleted or have separation disabled */
2064  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2065  continue;
2066  assert(SCIPconsIsActive(conss[c]));
2067 
2068  consdata = SCIPconsGetData(conss[c]);
2069  assert(consdata != NULL);
2070 
2071  /* TODO we could remember for which constraints there is a chance that we would add anything,
2072  * i.e., there is some convex-like expression, and skip other constraints
2073  */
2074 
2075  ENFOLOG(
2076  {
2077  int i;
2078  SCIPinfoMessage(scip, enfologfile, " constraint ");
2079  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2080  SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2081  for( i = 0; i < consdata->nvarexprs; ++i )
2082  {
2083  SCIP_VAR* var;
2084  var = SCIPgetVarExprVar(consdata->varexprs[i]);
2085  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2086  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2087  }
2088  })
2089 
2090  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2091  assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2092 
2093  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2094  {
2095  SCIP_EXPR_OWNERDATA* ownerdata;
2096 
2097  ownerdata = SCIPexprGetOwnerData(expr);
2098  assert(ownerdata != NULL);
2099 
2100  /* we can only generate a cut from an estimator if there is an auxvar */
2101  if( ownerdata->auxvar == NULL )
2102  continue;
2103 
2104  /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2105  assert(SCIPexprGetEvalTag(expr) == soltag);
2106  assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2107  SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2108 
2109  /* generate cuts from estimators of each nonlinear handler that provides estimates */
2110  for( e = 0; e < ownerdata->nenfos; ++e )
2111  {
2112  SCIP_NLHDLR* nlhdlr;
2113 
2114  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2115  assert(nlhdlr != NULL);
2116 
2117  /* skip nlhdlr that does not implement estimate (so it does enfo) */
2118  if( !SCIPnlhdlrHasEstimate(nlhdlr) )
2119  continue;
2120 
2121  /* skip nlhdlr that does not participate in separation or looks like it would give only locally-valid estimators
2122  * (because it uses activities on vars/auxvars)
2123  */
2124  if( ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 || ownerdata->enfos[e]->sepaaboveusesactivity) &&
2125  ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 || ownerdata->enfos[e]->sepabelowusesactivity) )
2126  continue;
2127 
2128  /* skip nlhdlr_default on sum, as the estimator doesn't depend on the reference point (expr is linear in auxvars) */
2129  if( SCIPisExprSum(scip, expr) && strcmp(SCIPnlhdlrGetName(nlhdlr), "default") == 0 )
2130  continue;
2131 
2132  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables, since some nlhdlr expect this before their estimate is called */
2133  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
2134  ENFOLOG(
2135  SCIPinfoMessage(scip, enfologfile, " expr ");
2136  SCIPprintExpr(scip, expr, enfologfile);
2137  SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g, nlhdlr <%s> auxvalue: %.15g\n",
2138  (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar), SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
2139  )
2140  /* due to setting values of auxvars to expr values in sol, the auxvalue should equal to expr evalvalue */
2141  assert(SCIPisEQ(scip, ownerdata->enfos[e]->auxvalue, SCIPexprGetEvalValue(expr)));
2142 
2143  /* if nlhdlr wants to be called for overestimate and does not use local bounds, then call estimate of nlhdlr */
2144  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) && !ownerdata->enfos[e]->sepaaboveusesactivity )
2145  {
2146  SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, TRUE, rowpreps) );
2147  }
2148 
2149  /* if nlhdlr wants to be called for underestimate and does not use local bounds, then call estimate of nlhdlr */
2150  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) && !ownerdata->enfos[e]->sepabelowusesactivity )
2151  {
2152  SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, FALSE, rowpreps) );
2153  }
2154  }
2155  }
2156  }
2157 
2158  SCIPfreeExpriter(&it);
2159  SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
2160 
2161  return SCIP_OKAY;
2162 }
2163 
2164 /** processes the event that a new primal solution has been found */
2165 static
2166 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2168  SCIP_CONSHDLR* conshdlr;
2169  SCIP_CONSHDLRDATA* conshdlrdata;
2170  SCIP_SOL* sol;
2171 
2172  assert(scip != NULL);
2173  assert(event != NULL);
2174  assert(eventdata != NULL);
2175  assert(eventhdlr != NULL);
2176  assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND);
2177 
2178  conshdlr = (SCIP_CONSHDLR*)eventdata;
2179 
2180  if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2181  return SCIP_OKAY;
2182 
2183  sol = SCIPeventGetSol(event);
2184  assert(sol != NULL);
2185 
2186  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2187  assert(conshdlrdata != NULL);
2188 
2189  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2190  * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2191  * from the tree, but postprocessed via proposeFeasibleSolution
2192  */
2193  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2194  return SCIP_OKAY;
2195 
2196  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2197 
2198  SCIP_CALL( addTightEstimatorCuts(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol) );
2199 
2200  return SCIP_OKAY;
2201 }
2202 
2203 /** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2204  *
2205  * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2206  * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2207  *
2208  * Nothing will happen if SCIP is not in presolve or solve.
2209  */
2210 static
2212  SCIP* scip, /**< SCIP data structure */
2213  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2214  SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2215  SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2216  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2217  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2218  )
2219 {
2220  SCIP_VAR* var;
2221  SCIP_Bool tightenedlb;
2222  SCIP_Bool tightenedub;
2223  SCIP_Bool force;
2224 
2225  assert(scip != NULL);
2226  assert(conshdlr != NULL);
2227  assert(expr != NULL);
2228  assert(cutoff != NULL);
2229 
2230  /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2231  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, bounds));
2232 
2233  *cutoff = FALSE;
2234 
2235  /* do not tighten variable in problem stage (important for unittests)
2236  * TODO put some kind of #ifdef UNITTEST around this
2237  */
2239  return SCIP_OKAY;
2240 
2241  var = SCIPgetExprAuxVarNonlinear(expr);
2242  if( var == NULL )
2243  return SCIP_OKAY;
2244 
2245  /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2246  force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2247 
2248  /* try to tighten lower bound of (auxiliary) variable */
2249  SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2250  if( tightenedlb )
2251  {
2252  if( ntightenings != NULL )
2253  ++*ntightenings;
2254  SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2255  }
2256  if( *cutoff )
2257  {
2258  SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2259  return SCIP_OKAY;
2260  }
2261 
2262  /* try to tighten upper bound of (auxiliary) variable */
2263  SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2264  if( tightenedub )
2265  {
2266  if( ntightenings != NULL )
2267  ++*ntightenings;
2268  SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2269  }
2270  if( *cutoff )
2271  {
2272  SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2273  return SCIP_OKAY;
2274  }
2275 
2276  /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2277  * that seems unnecessary and we could easily undo this here, e.g.,
2278  * if( tightenedlb ) expr->activity.inf = bounds.inf
2279  */
2280 
2281  return SCIP_OKAY;
2282 }
2283 
2284 /** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2285  * and tries to tighten the bounds of the auxiliary variables accordingly
2286  */
2287 static
2289  SCIP* scip, /**< SCIP data structure */
2290  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2291  SCIP_EXPR* rootexpr, /**< expression */
2292  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2293  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2294  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2295  )
2296 {
2297  SCIP_EXPRITER* it;
2298  SCIP_EXPR* expr;
2299  SCIP_EXPR_OWNERDATA* ownerdata;
2300  SCIP_CONSHDLRDATA* conshdlrdata;
2301 
2302  assert(scip != NULL);
2303  assert(rootexpr != NULL);
2304 
2305  if( infeasible != NULL )
2306  *infeasible = FALSE;
2307  if( ntightenings != NULL )
2308  *ntightenings = 0;
2309 
2310  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2311  assert(conshdlrdata != NULL);
2312 
2313  /* if value is valid and empty, then we cannot improve, so do nothing */
2314  if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2315  {
2316  SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2317 
2318  if( infeasible != NULL )
2319  *infeasible = TRUE;
2320 
2321  /* just update tag to curboundstag */
2322  SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2323 
2324  return SCIP_OKAY;
2325  }
2326 
2327  /* if value is up-to-date, then nothing to do */
2328  if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2329  {
2330  SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2331 
2332  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2333 
2334  return SCIP_OKAY;
2335  }
2336 
2337  ownerdata = SCIPexprGetOwnerData(rootexpr);
2338  assert(ownerdata != NULL);
2339 
2340  /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2341  * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2342  * during detect, we are in some in-between state where we may want to eval activity
2343  * on exprs that we did not notify about their activity usage
2344  */
2345  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2346  {
2347 #ifdef DEBUG_PROP
2348  SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2349 #endif
2350  SCIPABORT();
2351  return SCIP_OKAY;
2352  }
2353 
2354  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2355  SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2357 
2358  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2359  {
2360  switch( SCIPexpriterGetStageDFS(it) )
2361  {
2363  {
2364  /* skip child if it has been evaluated already */
2365  SCIP_EXPR* child;
2366 
2367  child = SCIPexpriterGetChildExprDFS(it);
2368  if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2369  {
2370  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2371  *infeasible = TRUE;
2372 
2373  expr = SCIPexpriterSkipDFS(it);
2374  continue;
2375  }
2376 
2377  break;
2378  }
2379 
2381  {
2382  SCIP_INTERVAL activity;
2383 
2384  /* we should not have entered this expression if its activity was already up to date */
2385  assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2386 
2387  ownerdata = SCIPexprGetOwnerData(expr);
2388  assert(ownerdata != NULL);
2389 
2390  /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2391  * so we can assume that the activity is up to date for all these variables
2392  * UNLESS we changed the method used to evaluate activity of variable expressions
2393  * or we currently use global bounds (varevents are catched for local bound changes only)
2394  */
2395  if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2396  SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2397  {
2398 #ifndef NDEBUG
2399  SCIP_INTERVAL exprhdlrinterval;
2400 
2401  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2402  assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2403  assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2404 #endif
2405 #ifdef DEBUG_PROP
2406  SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2407 #endif
2408  SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2409 
2410  break;
2411  }
2412 
2413  if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2414  {
2415  /* start with entire activity if current one is invalid */
2417  }
2419  {
2420  /* If already empty, then don't try to compute even better activity.
2421  * If cons_nonlinear were alone, then we should have noted that we are infeasible
2422  * so an assert(infeasible == NULL || *infeasible) should work here.
2423  * However, after reporting a cutoff due to expr->activity being empty,
2424  * SCIP may wander to a different node and call propagation again.
2425  * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2426  * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2427  * we will still have expr->activity being empty, but will have forgotten
2428  * that we found infeasibility here before (!2221#note_134120).
2429  * Therefore we just set *infeasibility=TRUE here and stop.
2430  */
2431  if( infeasible != NULL )
2432  *infeasible = TRUE;
2433  SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2434  break;
2435  }
2436  else
2437  {
2438  /* start with current activity, since it is valid */
2439  activity = SCIPexprGetActivity(expr);
2440  }
2441 
2442  /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2443  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2444  {
2445 #ifdef DEBUG_PROP
2446  SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2447 #endif
2448  break;
2449  }
2450 
2451 #ifdef DEBUG_PROP
2452  SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2453  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2454  SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2455 #endif
2456 
2457  /* run interval eval of nonlinear handlers or expression handler */
2458  if( ownerdata->nenfos > 0 )
2459  {
2460  SCIP_NLHDLR* nlhdlr;
2461  SCIP_INTERVAL nlhdlrinterval;
2462  int e;
2463 
2464  /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2465  for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2466  {
2467  /* skip nlhdlr if it does not want to participate in activity computation */
2468  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2469  continue;
2470 
2471  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2472  assert(nlhdlr != NULL);
2473 
2474  /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2475  if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2476  continue;
2477 
2478  /* let nlhdlr evaluate current expression */
2479  nlhdlrinterval = activity;
2480  SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2481  &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2482 #ifdef DEBUG_PROP
2483  SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2484 #endif
2485 
2486  /* update activity by intersecting with computed activity */
2487  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2488 #ifdef DEBUG_PROP
2489  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2490 #endif
2491  }
2492  }
2493  else
2494  {
2495  /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2496  SCIP_INTERVAL exprhdlrinterval = activity;
2497  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2498 #ifdef DEBUG_PROP
2499  SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2500 #endif
2501 
2502  /* update expr->activity by intersecting with computed activity */
2503  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2504 #ifdef DEBUG_PROP
2505  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2506 #endif
2507  }
2508 
2509  /* if expression is integral, then we try to tighten the interval bounds a bit
2510  * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2511  * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2512  * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2513  * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2514  * (constants should be ok, too)
2515  */
2516  if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2517  {
2518  if( activity.inf > -SCIP_INTERVAL_INFINITY )
2519  activity.inf = SCIPceil(scip, activity.inf);
2520  if( activity.sup < SCIP_INTERVAL_INFINITY )
2521  activity.sup = SCIPfloor(scip, activity.sup);
2522 #ifdef DEBUG_PROP
2523  SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2524 #endif
2525  }
2526 
2527  /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2528  * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2529  */
2530  if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2531  {
2532  SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2533  SCIPintervalSetEmpty(&activity);
2534  }
2535 
2536  /* now finally store activity in expr */
2537  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2538 
2540  {
2541  if( infeasible != NULL )
2542  *infeasible = TRUE;
2543  }
2544  else if( tightenauxvars && ownerdata->auxvar != NULL )
2545  {
2546  SCIP_Bool tighteninfeasible;
2547 
2548  SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2549  if( tighteninfeasible )
2550  {
2551  if( infeasible != NULL )
2552  *infeasible = TRUE;
2553  SCIPintervalSetEmpty(&activity);
2554  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2555  }
2556  }
2557 
2558  break;
2559  }
2560 
2561  default:
2562  /* you should never be here */
2563  SCIPerrorMessage("unexpected iterator stage\n");
2564  SCIPABORT();
2565  break;
2566  }
2567 
2568  expr = SCIPexpriterGetNext(it);
2569  }
2570 
2571  SCIPfreeExpriter(&it);
2572 
2573  return SCIP_OKAY;
2574 }
2575 
2576 /** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2577  *
2578  * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2579  *
2580  * If `subsetsufficient` is FALSE, then we require
2581  * - a change from an unbounded interval to a bounded one, or
2582  * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2583  * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2584  */
2585 static
2587  SCIP* scip, /**< SCIP data structure */
2588  SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2589  SCIP_INTERVAL newinterval, /**< new interval */
2590  SCIP_INTERVAL oldinterval /**< old interval */
2591  )
2592 {
2593  assert(scip != NULL);
2594  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2595  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2596 
2597  if( subsetsufficient )
2598  /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2599  return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2600 
2601  /* check whether lower bound of interval becomes finite */
2602  if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2603  return TRUE;
2604 
2605  /* check whether upper bound of interval becomes finite */
2606  if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2607  return TRUE;
2608 
2609  /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2610  if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2611  return TRUE;
2612 
2613  /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2614  if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2615  return TRUE;
2616 
2617  /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2618  if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2619  return TRUE;
2620 
2621  return FALSE;
2622 }
2623 
2624 /** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2625  *
2626  * The expression will be traversed in breadth first search by using this queue.
2627  *
2628  * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2629  * forwardPropExpr() before calling this function.
2630  *
2631  * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2632  */
2633 static
2635  SCIP* scip, /**< SCIP data structure */
2636  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2637  SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2638  int* ntightenings /**< buffer to store the number of (variable) tightenings */
2639  )
2640 {
2641  SCIP_CONSHDLRDATA* conshdlrdata;
2642  SCIP_EXPR* expr;
2643  SCIP_EXPR_OWNERDATA* ownerdata;
2644 
2645  assert(infeasible != NULL);
2646  assert(ntightenings != NULL);
2647 
2648  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2649  assert(conshdlrdata != NULL);
2650 
2651  *ntightenings = 0;
2652 
2653  /* main loop that calls reverse propagation for expressions on the queue
2654  * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2655  */
2656  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2657  {
2658  SCIP_INTERVAL propbounds;
2659  int e;
2660 
2661  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2662  assert(expr != NULL);
2663 
2664  ownerdata = SCIPexprGetOwnerData(expr);
2665  assert(ownerdata != NULL);
2666 
2667  assert(ownerdata->inpropqueue);
2668  /* mark that the expression is not in the queue anymore */
2669  ownerdata->inpropqueue = FALSE;
2670 
2671  /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2672  * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2673  */
2674  assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2675  assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2676  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2677 
2678  /* this intersects propbounds with activity and auxvar bounds
2679  * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2680  * auxvar bounds separately, so disabling this for now
2681  */
2682 #ifdef SCIP_DISABLED_CODE
2683  propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2684  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, propbounds) )
2685  {
2686  *infeasible = TRUE;
2687  break;
2688  }
2689 #else
2690  propbounds = ownerdata->propbounds;
2691 #endif
2692 
2693  if( ownerdata->nenfos > 0 )
2694  {
2695  /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2696  for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2697  {
2698  SCIP_NLHDLR* nlhdlr;
2699  int nreds;
2700 
2701  /* skip nlhdlr if it does not want to participate in activity computation */
2702  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2703  continue;
2704 
2705  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2706  assert(nlhdlr != NULL);
2707 
2708  /* call the reverseprop of the nlhdlr */
2709 #ifdef SCIP_DEBUG
2710  SCIPdebugMsg(scip, "call reverse propagation for ");
2711  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2712  SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2713 #endif
2714 
2715  nreds = 0;
2716  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2717  assert(nreds >= 0);
2718  *ntightenings += nreds;
2719  }
2720  }
2722  {
2723  /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2724  SCIP_INTERVAL* childrenbounds;
2725  int c;
2726 
2727 #ifdef SCIP_DEBUG
2728  SCIPdebugMsg(scip, "call reverse propagation for ");
2729  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2730  SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2731 #endif
2732 
2733  /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2734  * been initialized in detectNlhdlr yet (nenfos < 0)
2735  */
2736  assert(ownerdata->nenfos < 0);
2737 
2738  SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2739  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2740  childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2741 
2742  /* call the reverseprop of the exprhdlr */
2743  SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2744 
2745  if( !*infeasible )
2746  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2747  {
2748  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2749  }
2750 
2751  SCIPfreeBufferArray(scip, &childrenbounds);
2752  }
2753  }
2754 
2755  /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2756  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2757  {
2758  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2759  assert(expr != NULL);
2760 
2761  ownerdata = SCIPexprGetOwnerData(expr);
2762  assert(ownerdata != NULL);
2763 
2764  /* mark that the expression is not in the queue anymore */
2765  ownerdata->inpropqueue = FALSE;
2766  }
2767 
2768  return SCIP_OKAY;
2769 }
2770 
2771 /** calls domain propagation for a given set of constraints
2772  *
2773  * The algorithm alternates calls of forward and reverse propagation.
2774  * Forward propagation ensures that activity of expressions is up to date.
2775  * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2776  * [lhs,rhs] interval as starting point.
2777  *
2778  * The propagation algorithm works as follows:
2779  * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2780  * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2781  * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2782  * provide tighter bounds
2783  * 3. apply reverse propagation to all collected expressions; don't explore
2784  * sub-expressions which have not changed since the beginning of the propagation loop
2785  * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2786  *
2787  * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2788  * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2789  * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2790  *
2791  * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2792  * e.g., try less to propagate on convex constraints?
2793  */
2794 static
2796  SCIP* scip, /**< SCIP data structure */
2797  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2798  SCIP_CONS** conss, /**< constraints to propagate */
2799  int nconss, /**< total number of constraints */
2800  SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2801  SCIP_RESULT* result, /**< pointer to store the result */
2802  int* nchgbds /**< buffer to add the number of changed bounds */
2803  )
2804 {
2805  SCIP_CONSHDLRDATA* conshdlrdata;
2806  SCIP_CONSDATA* consdata;
2807  SCIP_EXPR_OWNERDATA* ownerdata;
2808  SCIP_Bool cutoff = FALSE;
2809  SCIP_INTERVAL conssides;
2810  int ntightenings;
2811  int roundnr;
2812  SCIP_EXPRITER* revpropcollectit = NULL;
2813  int i;
2814 
2815  assert(scip != NULL);
2816  assert(conshdlr != NULL);
2817  assert(conss != NULL);
2818  assert(nconss >= 0);
2819  assert(result != NULL);
2820  assert(nchgbds != NULL);
2821  assert(*nchgbds >= 0);
2822 
2823  /* no constraints to propagate */
2824  if( nconss == 0 )
2825  {
2826  *result = SCIP_DIDNOTRUN;
2827  return SCIP_OKAY;
2828  }
2829 
2830  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2831  assert(conshdlrdata != NULL);
2832 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2833  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2834 #endif
2835  assert(!conshdlrdata->globalbounds);
2836 
2837  *result = SCIP_DIDNOTFIND;
2838  roundnr = 0;
2839 
2840  /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2841  conshdlrdata->forceboundtightening = force;
2842 
2843  /* invalidate all propbounds (probably not needed) */
2844  ++conshdlrdata->curpropboundstag;
2845 
2846  /* create iterator that we will use if we need to look at all auxvars */
2847  if( conshdlrdata->propauxvars )
2848  {
2849  SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2850  }
2851 
2852  /* main propagation loop */
2853  do
2854  {
2855  SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2856 
2857  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2858 
2859  /* apply forward propagation (update expression activities)
2860  * and add promising root expressions into queue for reversepropagation
2861  */
2862  for( i = 0; i < nconss; ++i )
2863  {
2864  consdata = SCIPconsGetData(conss[i]);
2865  assert(consdata != NULL);
2866 
2867  /* skip deleted, non-active, or propagation-disabled constraints */
2868  if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2869  continue;
2870 
2871  /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2872  * activity didn't change
2873  */
2874  if( consdata->ispropagated )
2875  continue;
2876 
2877  /* update activities in expression */
2878  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2879  SCIPdebugPrintCons(scip, conss[i], NULL);
2880 
2881  ntightenings = 0;
2882  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2883  assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2884 
2885  if( cutoff )
2886  {
2887  SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2888  *result = SCIP_CUTOFF;
2889  break;
2890  }
2891 
2892  ownerdata = SCIPexprGetOwnerData(consdata->expr);
2893 
2894  /* 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 */
2895  if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2896  {
2897  /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2898  * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2899  * so taking auxvar bounds is enough)
2900  */
2901  if( ownerdata->auxvar == NULL )
2902  {
2903  /* relax sides by SCIPepsilon() and handle infinite sides */
2904  SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2905  SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2906  SCIPintervalSetBounds(&conssides, lhs, rhs);
2907  }
2908  else
2909  {
2910  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2911  }
2912  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2913  }
2914  else
2915  {
2916  /* check whether bounds of any auxvar used in constraint provides a tightening
2917  * (for the root expression, bounds of auxvar are initially set to constraint sides)
2918  * but skip exprs that have an auxvar, but do not participate in propagation
2919  */
2920  SCIP_EXPR* expr;
2921 
2922  assert(revpropcollectit != NULL);
2923  SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2924  for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2925  {
2926  ownerdata = SCIPexprGetOwnerData(expr);
2927  assert(ownerdata != NULL);
2928 
2929  if( ownerdata->auxvar == NULL )
2930  continue;
2931 
2932  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2933  continue;
2934 
2935  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2936  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2937  }
2938  }
2939 
2940  if( cutoff )
2941  {
2942  SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2943  *result = SCIP_CUTOFF;
2944  break;
2945  }
2946 
2947  assert(ntightenings >= 0);
2948  if( ntightenings > 0 )
2949  {
2950  *nchgbds += ntightenings;
2951  *result = SCIP_REDUCEDDOM;
2952  }
2953 
2954  /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2955  consdata->ispropagated = TRUE;
2956  }
2957 
2958  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2959  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2960  assert(ntightenings >= 0);
2961  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2962 
2963  if( cutoff )
2964  {
2965  SCIPdebugMsg(scip, " -> cutoff\n");
2966  *result = SCIP_CUTOFF;
2967  break;
2968  }
2969 
2970  if( ntightenings > 0 )
2971  {
2972  *nchgbds += ntightenings;
2973  *result = SCIP_REDUCEDDOM;
2974  }
2975  }
2976  while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2977 
2978  if( conshdlrdata->propauxvars )
2979  {
2980  SCIPfreeExpriter(&revpropcollectit);
2981  }
2982 
2983  conshdlrdata->forceboundtightening = FALSE;
2984 
2985  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2986  ++conshdlrdata->curpropboundstag;
2987 
2988  return SCIP_OKAY;
2989 }
2990 
2991 /** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2992  *
2993  * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2994  *
2995  * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2996  * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2997  */
2998 static
3000  SCIP* scip, /**< SCIP data structure */
3001  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3002  SCIP_CONS** conss, /**< constraints to propagate */
3003  int nconss, /**< total number of constraints */
3004  SCIP_RESULT* result, /**< pointer to store the result */
3005  int* nchgbds /**< buffer to add the number of changed bounds */
3006  )
3007 {
3008  SCIP_CONSDATA* consdata;
3009  SCIP_EXPRITER* it;
3010  SCIP_EXPR* expr;
3011  SCIP_EXPR_OWNERDATA* ownerdata;
3012  SCIP_Bool cutoff = FALSE;
3013  int ntightenings;
3014  int c;
3015  int e;
3016 
3017  assert(scip != NULL);
3018  assert(conshdlr != NULL);
3019  assert(conss != NULL);
3020  assert(nconss >= 0);
3021  assert(result != NULL);
3022  assert(nchgbds != NULL);
3023  assert(*nchgbds >= 0);
3024 
3025 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
3026  assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
3027 #endif
3028  assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
3029  assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
3030 
3031  *result = SCIP_DIDNOTFIND;
3032 
3033  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3035 
3036  for( c = 0; c < nconss && !cutoff; ++c )
3037  {
3038  /* skip deleted, non-active, or propagation-disabled constraints */
3039  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
3040  continue;
3041 
3042  consdata = SCIPconsGetData(conss[c]);
3043  assert(consdata != NULL);
3044 
3045  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
3046  {
3047  ownerdata = SCIPexprGetOwnerData(expr);
3048  assert(ownerdata != NULL);
3049 
3050  /* call reverseprop for those nlhdlr that participate in this expr's activity computation
3051  * this will propagate the current activity
3052  */
3053  for( e = 0; e < ownerdata->nenfos; ++e )
3054  {
3055  SCIP_NLHDLR* nlhdlr;
3056  assert(ownerdata->enfos[e] != NULL);
3057 
3058  nlhdlr = ownerdata->enfos[e]->nlhdlr;
3059  assert(nlhdlr != NULL);
3060  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
3061  continue;
3062 
3063  SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
3064  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
3065  ntightenings = 0;
3066  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
3067  SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
3068 
3069  if( cutoff )
3070  {
3071  /* stop everything if we detected infeasibility */
3072  SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3073  *result = SCIP_CUTOFF;
3074  break;
3075  }
3076 
3077  assert(ntightenings >= 0);
3078  if( ntightenings > 0 )
3079  {
3080  *nchgbds += ntightenings;
3081  *result = SCIP_REDUCEDDOM;
3082  }
3083  }
3084  }
3085  }
3086 
3087  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
3088  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
3089  assert(ntightenings >= 0);
3090 
3091  if( cutoff )
3092  {
3093  SCIPdebugMsg(scip, " -> cutoff\n");
3094  *result = SCIP_CUTOFF;
3095  }
3096  else if( ntightenings > 0 )
3097  {
3098  *nchgbds += ntightenings;
3099  *result = SCIP_REDUCEDDOM;
3100  }
3101 
3102  SCIPfreeExpriter(&it);
3103 
3104  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
3105  ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
3106 
3107  return SCIP_OKAY;
3108 }
3109 
3110 /** propagates variable locks through expression and adds locks to variables */
3111 static
3113  SCIP* scip, /**< SCIP data structure */
3114  SCIP_EXPR* expr, /**< expression */
3115  int nlockspos, /**< number of positive locks */
3116  int nlocksneg /**< number of negative locks */
3117  )
3118 {
3119  SCIP_EXPR_OWNERDATA* ownerdata;
3120  SCIP_EXPRITER* it;
3121  SCIP_EXPRITER_USERDATA ituserdata;
3122 
3123  assert(expr != NULL);
3124 
3125  /* if no locks, then nothing to propagate */
3126  if( nlockspos == 0 && nlocksneg == 0 )
3127  return SCIP_OKAY;
3128 
3129  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3132  assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3133 
3134  /* store locks in root node */
3135  ituserdata.intvals[0] = nlockspos;
3136  ituserdata.intvals[1] = nlocksneg;
3137  SCIPexpriterSetCurrentUserData(it, ituserdata);
3138 
3139  while( !SCIPexpriterIsEnd(it) )
3140  {
3141  /* collect locks */
3142  ituserdata = SCIPexpriterGetCurrentUserData(it);
3143  nlockspos = ituserdata.intvals[0];
3144  nlocksneg = ituserdata.intvals[1];
3145 
3146  ownerdata = SCIPexprGetOwnerData(expr);
3147 
3148  switch( SCIPexpriterGetStageDFS(it) )
3149  {
3151  {
3152  if( SCIPisExprVar(scip, expr) )
3153  {
3154  /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3155  SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3156  }
3157 
3158  /* add locks to expression */
3159  ownerdata->nlockspos += nlockspos;
3160  ownerdata->nlocksneg += nlocksneg;
3161 
3162  /* add monotonicity information if expression has been locked for the first time */
3163  if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3165  {
3166  int i;
3167 
3168  assert(ownerdata->monotonicity == NULL);
3169  assert(ownerdata->monotonicitysize == 0);
3170 
3171  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3172  ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3173 
3174  /* store the monotonicity for each child */
3175  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3176  {
3177  SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3178  }
3179  }
3180  break;
3181  }
3182 
3184  {
3185  /* remove monotonicity information if expression has been unlocked */
3186  if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3187  {
3188  assert(ownerdata->monotonicitysize > 0);
3189  /* keep this assert for checking whether someone changed an expression without updating locks properly */
3190  assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3191 
3192  SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3193  ownerdata->monotonicitysize = 0;
3194  }
3195  break;
3196  }
3197 
3199  {
3200  SCIP_MONOTONE monotonicity;
3201 
3202  /* get monotonicity of child */
3203  /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3204  * SCIPcallExprMonotonicity
3205  */
3206  monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3207 
3208  /* compute resulting locks of the child expression */
3209  switch( monotonicity )
3210  {
3211  case SCIP_MONOTONE_INC:
3212  ituserdata.intvals[0] = nlockspos;
3213  ituserdata.intvals[1] = nlocksneg;
3214  break;
3215  case SCIP_MONOTONE_DEC:
3216  ituserdata.intvals[0] = nlocksneg;
3217  ituserdata.intvals[1] = nlockspos;
3218  break;
3219  case SCIP_MONOTONE_UNKNOWN:
3220  ituserdata.intvals[0] = nlockspos + nlocksneg;
3221  ituserdata.intvals[1] = nlockspos + nlocksneg;
3222  break;
3223  case SCIP_MONOTONE_CONST:
3224  ituserdata.intvals[0] = 0;
3225  ituserdata.intvals[1] = 0;
3226  break;
3227  }
3228  /* set locks in child expression */
3229  SCIPexpriterSetChildUserData(it, ituserdata);
3230 
3231  break;
3232  }
3233 
3234  default :
3235  /* you should never be here */
3236  SCIPABORT();
3237  break;
3238  }
3239 
3240  expr = SCIPexpriterGetNext(it);
3241  }
3242 
3243  SCIPfreeExpriter(&it);
3244 
3245  return SCIP_OKAY;
3246 }
3247 
3248 /** main function for adding locks to expressions and variables
3249  *
3250  * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3251  * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3252  * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3253  * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3254  * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3255  * the computed monotonicity information of each expression until all locks of an expression have been removed,
3256  * which implies that updating the monotonicity information during the next locking of this expression does not
3257  * break existing locks.
3258  *
3259  * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3260  * locks from an expression and repropagating them after the structural changes have been applied.
3261  * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3262  * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3263  */
3264 static
3266  SCIP* scip, /**< SCIP data structure */
3267  SCIP_CONS* cons, /**< nonlinear constraint */
3268  int nlockspos, /**< number of positive rounding locks */
3269  int nlocksneg /**< number of negative rounding locks */
3270  )
3271 {
3272  SCIP_CONSDATA* consdata;
3273 
3274  assert(cons != NULL);
3275 
3276  if( nlockspos == 0 && nlocksneg == 0 )
3277  return SCIP_OKAY;
3278 
3279  consdata = SCIPconsGetData(cons);
3280  assert(consdata != NULL);
3281 
3282  /* no constraint sides -> nothing to lock */
3283  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3284  return SCIP_OKAY;
3285 
3286  /* remember locks */
3287  consdata->nlockspos += nlockspos;
3288  consdata->nlocksneg += nlocksneg;
3289 
3290  assert(consdata->nlockspos >= 0);
3291  assert(consdata->nlocksneg >= 0);
3292 
3293  /* compute locks for lock propagation */
3294  if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3295  {
3296  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3297  }
3298  else if( !SCIPisInfinity(scip, consdata->rhs) )
3299  {
3300  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3301  }
3302  else
3303  {
3304  assert(!SCIPisInfinity(scip, -consdata->lhs));
3305  SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3306  }
3307 
3308  return SCIP_OKAY;
3309 }
3310 
3311 /** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3312 static
3314  SCIP* scip, /**< SCIP data structure */
3315  SCIP_CONS* cons /**< nonlinear constraint */
3316  )
3317 {
3318  SCIP_CONSDATA* consdata;
3319 
3320  assert(scip != NULL);
3321  assert(cons != NULL);
3322 
3323  consdata = SCIPconsGetData(cons);
3324  assert(consdata != NULL);
3325  assert(consdata->expr != NULL);
3326 
3327  if( consdata->nlrow != NULL )
3328  {
3329  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3330  }
3331 
3332  /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3333  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3334  0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3335 
3336  if( SCIPisExprSum(scip, consdata->expr) )
3337  {
3338  /* if root is a sum, then split into linear and nonlinear terms */
3339  SCIP_EXPR* nonlinpart;
3340  SCIP_EXPR* child;
3341  SCIP_Real* coefs;
3342  int i;
3343 
3344  coefs = SCIPgetCoefsExprSum(consdata->expr);
3345 
3346  /* constant term of sum */
3347  SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3348 
3349  /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3350  SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3351 
3352  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3353  {
3354  child = SCIPexprGetChildren(consdata->expr)[i];
3355  if( SCIPisExprVar(scip, child) )
3356  {
3357  /* linear term */
3358  SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3359  }
3360  else
3361  {
3362  /* nonlinear term */
3363  SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3364  }
3365  }
3366 
3367  if( SCIPexprGetNChildren(nonlinpart) > 0 )
3368  {
3369  /* add expression to nlrow (this will make a copy) */
3370  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3371  }
3372  SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3373  }
3374  else
3375  {
3376  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3377  }
3378 
3379  return SCIP_OKAY;
3380 }
3381 
3382 /** compares enfodata by enforcement priority of nonlinear handler
3383  *
3384  * If handlers have same enforcement priority, then compare by detection priority, then by name.
3385  */
3386 static
3387 SCIP_DECL_SORTPTRCOMP(enfodataCmp)
3389  SCIP_NLHDLR* h1;
3390  SCIP_NLHDLR* h2;
3391 
3392  assert(elem1 != NULL);
3393  assert(elem2 != NULL);
3394 
3395  h1 = ((EXPRENFO*)elem1)->nlhdlr;
3396  h2 = ((EXPRENFO*)elem2)->nlhdlr;
3397 
3398  assert(h1 != NULL);
3399  assert(h2 != NULL);
3400 
3403 
3406 
3407  return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3408 }
3409 
3410 /** install nlhdlrs in one expression */
3411 static
3413  SCIP* scip, /**< SCIP data structure */
3414  SCIP_EXPR* expr, /**< expression for which to run detection routines */
3415  SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3416  )
3417 {
3418  SCIP_EXPR_OWNERDATA* ownerdata;
3419  SCIP_CONSHDLRDATA* conshdlrdata;
3420  SCIP_NLHDLR_METHOD enforcemethodsallowed;
3421  SCIP_NLHDLR_METHOD enforcemethods;
3422  SCIP_NLHDLR_METHOD enforcemethodsnew;
3423  SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3424  SCIP_NLHDLR_METHOD nlhdlrparticipating;
3425  SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3426  int enfossize; /* allocated length of expr->enfos array */
3427  int h;
3428 
3429  assert(expr != NULL);
3430 
3431  ownerdata = SCIPexprGetOwnerData(expr);
3432  assert(ownerdata != NULL);
3433 
3434  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3435  assert(conshdlrdata != NULL);
3436  assert(conshdlrdata->auxvarid >= 0);
3437  assert(!conshdlrdata->indetect);
3438 
3439  /* there should be no enforcer yet and detection should not even have considered expr yet */
3440  assert(ownerdata->nenfos < 0);
3441  assert(ownerdata->enfos == NULL);
3442 
3443  /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3444  * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3445  * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3446  * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3447  * - if no one uses activity, then do not need activity methods
3448  */
3449  enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3450  if( ownerdata->nauxvaruses == 0 )
3451  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3452  else
3453  {
3454  if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3455  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3456  if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3457  enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3458  }
3459  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3460  enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3461 
3462  /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3463  assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3464 
3465  /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3466  enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3467 
3468  ownerdata->nenfos = 0;
3469  enfossize = 2;
3470  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3471  conshdlrdata->indetect = TRUE;
3472 
3473  SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3474  cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3475  (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3476  (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3477  (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3478 
3479  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3480  {
3481  SCIP_NLHDLR* nlhdlr;
3482 
3483  nlhdlr = conshdlrdata->nlhdlrs[h];
3484  assert(nlhdlr != NULL);
3485 
3486  /* skip disabled nlhdlrs */
3487  if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3488  continue;
3489 
3490  /* call detect routine of nlhdlr */
3491  nlhdlrexprdata = NULL;
3492  enforcemethodsnew = enforcemethods;
3493  nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3494  conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3495  conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3496  /* coverity[forward_null] */
3497  SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3498 
3499  /* nlhdlr might have claimed more than needed: clean up sepa flags */
3500  nlhdlrparticipating &= enforcemethodsallowed;
3501 
3502  /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3503  assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3504 
3505  /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3506  * They are also cleaned up here to ensure that only the needed methods are claimed.
3507  */
3508  nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3509 
3510  /* nlhdlr needs to participate for the methods it is enforcing */
3511  assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3512 
3513  if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3514  {
3515  /* nlhdlr might not have detected anything, or all set flags might have been removed by
3516  * clean up; in the latter case, we may need to free nlhdlrexprdata */
3517 
3518  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3519  if( nlhdlrexprdata != NULL )
3520  {
3521  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3522  }
3523  /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3524  assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3525 
3526  SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3527 
3528  continue;
3529  }
3530 
3531  SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3532  SCIPnlhdlrGetName(nlhdlr),
3533  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3534  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3535  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3536 
3537  /* store nlhdlr and its data */
3538  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3539  SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3540  ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3541  ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3542  ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3543  ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3544  ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3545  ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3546  ownerdata->nenfos++;
3547 
3548  /* update enforcement flags */
3549  enforcemethods = enforcemethodsnew;
3550  }
3551 
3552  conshdlrdata->indetect = FALSE;
3553 
3554  /* stop if an enforcement method is missing but we are already in solving stage
3555  * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3556  */
3557  if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3558  {
3559  SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3560  return SCIP_ERROR;
3561  }
3562 
3563  assert(ownerdata->nenfos > 0);
3564 
3565  /* sort nonlinear handlers by enforcement priority, in decreasing order */
3566  if( ownerdata->nenfos > 1 )
3567  SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3568 
3569  /* resize enfos array to be nenfos long */
3570  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3571 
3572  return SCIP_OKAY;
3573 }
3574 
3575 /** detect nlhdlrs that can handle the expressions */
3576 static
3578  SCIP* scip, /**< SCIP data structure */
3579  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3580  SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3581  int nconss /**< total number of constraints */
3582  )
3583 {
3584  SCIP_CONSHDLRDATA* conshdlrdata;
3585  SCIP_CONSDATA* consdata;
3586  SCIP_EXPR* expr;
3587  SCIP_EXPR_OWNERDATA* ownerdata;
3588  SCIP_EXPRITER* it;
3589  int i;
3590 
3591  assert(conss != NULL || nconss == 0);
3592  assert(nconss >= 0);
3593  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 */
3594 
3595  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3596  assert(conshdlrdata != NULL);
3597 
3598  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3600 
3601  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3602  {
3603  /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3604  * for example, this happens if globally valid nonlinear constraints are added during the tree search
3605  */
3607  conshdlrdata->globalbounds = TRUE;
3608  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3609  }
3610 
3611  for( i = 0; i < nconss; ++i )
3612  {
3613  assert(conss != NULL && conss[i] != NULL);
3614 
3615  consdata = SCIPconsGetData(conss[i]);
3616  assert(consdata != NULL);
3617  assert(consdata->expr != NULL);
3618 
3619  /* if a constraint is separated, we currently need it to be initial, too
3620  * this is because INITLP will create the auxiliary variables that are used for any separation
3621  * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3622  */
3623  assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3624 
3625  ownerdata = SCIPexprGetOwnerData(consdata->expr);
3626  assert(ownerdata != NULL);
3627 
3628  /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3629  * then we would normally skip to run DETECT again
3630  * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3631  * thus, if expr is the root expression, we rerun DETECT
3632  */
3633  if( ownerdata->nenfos > 0 )
3634  {
3635  SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3636  assert(ownerdata->nenfos < 0);
3637  }
3638 
3639  /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3640  * this way we can treat the root expression like any other expression when enforcing via separation
3641  * if constraint will be propagated, then register activity usage of root expression
3642  * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3643  */
3644  conshdlrdata->indetect = TRUE;
3645  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, consdata->expr,
3646  SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3647  SCIPconsIsPropagated(conss[i]),
3648  FALSE, FALSE) );
3649  conshdlrdata->indetect = FALSE;
3650 
3651  /* compute integrality information for all subexpressions */
3652  SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3653 
3654  /* run detectNlhdlr on all expr where required */
3655  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3656  {
3657  ownerdata = SCIPexprGetOwnerData(expr);
3658  assert(ownerdata != NULL);
3659 
3660  /* skip exprs that we already looked at */
3661  if( ownerdata->nenfos >= 0 )
3662  continue;
3663 
3664  /* if there is use of the auxvar, then someone requires that
3665  * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3666  * thus, we need to find nlhdlrs that separate or estimate
3667  * if there is use of the activity, then there is someone requiring that
3668  * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3669  * thus, we need to find nlhdlrs that do interval-evaluation
3670  */
3671  if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3672  {
3673  SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3674 
3675  assert(ownerdata->nenfos >= 0);
3676  }
3677  else
3678  {
3679  /* remember that we looked at this expression during detectNlhdlrs
3680  * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3681  * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3682  * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3683  */
3684  ownerdata->nenfos = 0;
3685  }
3686  }
3687 
3688  /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3689  if( SCIPconsIsPropagated(conss[i]) )
3690  consdata->ispropagated = FALSE;
3691  }
3692 
3693  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3694  {
3695  /* ensure that the local bounds are used again when reevaluating the expressions later;
3696  * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3697  */
3699  conshdlrdata->globalbounds = FALSE;
3700  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3701  }
3702  else
3703  {
3704  /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3706  }
3707 
3708  SCIPfreeExpriter(&it);
3709 
3710  return SCIP_OKAY;
3711 }
3712 
3713 /** initializes (pre)solving data of constraints
3714  *
3715  * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3716  * not be modified.
3717  * In particular, this function
3718  * - runs the detection method of nlhldrs
3719  * - looks for unlocked linear variables
3720  * - checks curvature (if not in presolve)
3721  * - creates and add row to NLP (if not in presolve)
3722  *
3723  * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3724  * e.g., it should be called in INITSOL and for constraints that are added during solve.
3725  */
3726 static
3728  SCIP* scip, /**< SCIP data structure */
3729  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3730  SCIP_CONS** conss, /**< constraints */
3731  int nconss /**< number of constraints */
3732  )
3733 {
3734  int c;
3735 
3736  for( c = 0; c < nconss; ++c )
3737  {
3738  /* check for a linear variable that can be increase or decreased without harming feasibility */
3739  findUnlockedLinearVar(scip, conss[c]);
3740 
3742  {
3743  SCIP_CONSDATA* consdata;
3744  SCIP_Bool success = FALSE;
3745 
3746  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3747  assert(consdata != NULL);
3748  assert(consdata->expr != NULL);
3749 
3750  if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3751  {
3752  /* call the curvature detection algorithm of the convex nonlinear handler
3753  * Check only for those curvature that may result in a convex inequality, i.e.,
3754  * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3755  * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3756  */
3757  if( !SCIPisInfinity(scip, -consdata->lhs) )
3758  {
3759  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3760  if( success )
3761  consdata->curv = SCIP_EXPRCURV_CONCAVE;
3762  }
3763  if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3764  {
3765  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3766  if( success )
3767  consdata->curv = SCIP_EXPRCURV_CONVEX;
3768  }
3769  }
3770  else
3771  {
3772  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3773  {
3774  SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3775  consdata->curv = SCIP_EXPRCURV_LINEAR;
3776  }
3777  else
3778  {
3779  consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3780  }
3781  }
3782  SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3783 
3784  /* add nlrow representation to NLP, if NLP had been constructed */
3785  if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3786  {
3787  if( consdata->nlrow == NULL )
3788  {
3789  SCIP_CALL( createNlRow(scip, conss[c]) );
3790  assert(consdata->nlrow != NULL);
3791  }
3792  SCIPnlrowSetCurvature(consdata->nlrow, consdata->curv);
3793  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3794  }
3795  }
3796  }
3797 
3798  /* register non linear handlers */
3799  SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3800 
3801  return SCIP_OKAY;
3802 }
3803 
3804 /** deinitializes (pre)solving data of constraints
3805  *
3806  * This removes the initialization data created in initSolve().
3807  *
3808  * This function can be called in presolve and solve.
3809  *
3810  * TODO At the moment, it should not be called for a constraint if there are other constraints
3811  * that use the same expressions but still require their nlhdlr.
3812  * We should probably only decrement the auxvar and activity usage for the root expr and then
3813  * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3814  */
3815 static
3817  SCIP* scip, /**< SCIP data structure */
3818  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3819  SCIP_CONS** conss, /**< constraints */
3820  int nconss /**< number of constraints */
3821  )
3822 {
3823  SCIP_EXPRITER* it;
3824  SCIP_EXPR* expr;
3825  SCIP_CONSDATA* consdata;
3826  SCIP_Bool rootactivityvalid;
3827  int c;
3828 
3829  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3832 
3833  /* call deinitialization callbacks of expression and nonlinear handlers
3834  * free nonlinear handlers information from expressions
3835  * remove auxiliary variables and nactivityuses counts from expressions
3836  */
3837  for( c = 0; c < nconss; ++c )
3838  {
3839  assert(conss != NULL);
3840  assert(conss[c] != NULL);
3841 
3842  consdata = SCIPconsGetData(conss[c]);
3843  assert(consdata != NULL);
3844  assert(consdata->expr != NULL);
3845 
3846  /* check and remember whether activity in root is valid */
3847  rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3848 
3849  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3850  {
3851  SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3852 
3853  /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3854  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3855 
3856  /* remove quadratic info */
3857  SCIPfreeExprQuadratic(scip, expr);
3858 
3859  if( rootactivityvalid )
3860  {
3861  /* ensure activity is valid if consdata->expr activity is valid
3862  * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3863  * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3864  * so this childs activity would be invalid, which can generate confusion
3865  */
3866  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
3867  }
3868  }
3869 
3870  if( consdata->nlrow != NULL )
3871  {
3872  /* remove row from NLP, if still in solving
3873  * if we are in exitsolve, the whole NLP will be freed anyway
3874  */
3875  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3876  {
3877  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3878  }
3879 
3880  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3881  }
3882 
3883  /* forget about linear variables that can be increased or decreased without harming feasibility */
3884  consdata->linvardecr = NULL;
3885  consdata->linvarincr = NULL;
3886 
3887  /* forget about curvature */
3888  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3889  }
3890 
3891  SCIPfreeExpriter(&it);
3892 
3893  return SCIP_OKAY;
3894 }
3895 
3896 /** helper method to decide whether a given expression is product of at least two binary variables */
3897 static
3899  SCIP* scip, /**< SCIP data structure */
3900  SCIP_EXPR* expr /**< expression */
3901  )
3902 {
3903  int i;
3904 
3905  assert(expr != NULL);
3906 
3907  /* check whether the expression is a product */
3908  if( !SCIPisExprProduct(scip, expr) )
3909  return FALSE;
3910 
3911  /* don't consider products with a coefficient != 1 and products with a single child
3912  * simplification will take care of this expression later
3913  */
3914  if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3915  return FALSE;
3916 
3917  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3918  {
3919  SCIP_EXPR* child;
3920  SCIP_VAR* var;
3921  SCIP_Real ub;
3922  SCIP_Real lb;
3923 
3924  child = SCIPexprGetChildren(expr)[i];
3925  assert(child != NULL);
3926 
3927  if( !SCIPisExprVar(scip, child) )
3928  return FALSE;
3929 
3930  var = SCIPgetVarExprVar(child);
3931  lb = SCIPvarGetLbLocal(var);
3932  ub = SCIPvarGetUbLocal(var);
3933 
3934  /* check whether variable is integer and has [0,1] as variable bounds */
3935  if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3936  return FALSE;
3937  }
3938 
3939  return TRUE;
3940 }
3941 
3942 /** helper method to collect all bilinear binary product terms */
3943 static
3945  SCIP* scip, /**< SCIP data structure */
3946  SCIP_EXPR* sumexpr, /**< sum expression */
3947  SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3948  SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3949  int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3950  int* nterms /**< pointer to store the total number of bilinear binary terms */
3951  )
3952 {
3953  int i;
3954 
3955  assert(sumexpr != NULL);
3956  assert(SCIPisExprSum(scip, sumexpr));
3957  assert(xs != NULL);
3958  assert(ys != NULL);
3959  assert(childidxs != NULL);
3960  assert(nterms != NULL);
3961 
3962  *nterms = 0;
3963 
3964  for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3965  {
3966  SCIP_EXPR* child;
3967 
3968  child = SCIPexprGetChildren(sumexpr)[i];
3969  assert(child != NULL);
3970 
3971  if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3972  {
3975 
3976  assert(x != NULL);
3977  assert(y != NULL);
3978 
3979  if( x != y )
3980  {
3981  xs[*nterms] = x;
3982  ys[*nterms] = y;
3983  childidxs[*nterms] = i;
3984  ++(*nterms);
3985  }
3986  }
3987  }
3988 
3989  return SCIP_OKAY;
3990 }
3991 
3992 /** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3993 static
3995  SCIP* scip, /**< SCIP data structure */
3996  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3997  SCIP_CONS* cons, /**< constraint */
3998  SCIP_VAR* facvar, /**< variable that has been factorized */
3999  SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
4000  SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
4001  int nvars, /**< total number of variables in sum_j c_ij x_j */
4002  SCIP_EXPR** newexpr, /**< pointer to store the new expression */
4003  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4004  )
4005 {
4006  SCIP_VAR* auxvar;
4007  SCIP_CONS* newcons;
4008  SCIP_Real minact = 0.0;
4009  SCIP_Real maxact = 0.0;
4010  SCIP_Bool integral = TRUE;
4011  char name [SCIP_MAXSTRLEN];
4012  int i;
4013 
4014  assert(facvar != NULL);
4015  assert(vars != NULL);
4016  assert(nvars > 1);
4017  assert(newexpr != NULL);
4018 
4019  /* compute minimum and maximum activity of sum_j c_ij x_j */
4020  /* 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 */
4021  for( i = 0; i < nvars; ++i )
4022  {
4023  minact += MIN(coefs[i], 0.0);
4024  maxact += MAX(coefs[i], 0.0);
4025  integral = integral && SCIPisIntegral(scip, coefs[i]);
4026  }
4027  assert(minact <= maxact);
4028 
4029  /* create and add auxiliary variable */
4030  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4031  SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
4032  SCIP_CALL( SCIPaddVar(scip, auxvar) );
4033 
4034  /* create and add z - maxact x <= 0 */
4035  if( !SCIPisZero(scip, maxact) )
4036  {
4037  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4038  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
4039  SCIP_CALL( SCIPaddCons(scip, newcons) );
4040  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4041  if( naddconss != NULL )
4042  ++(*naddconss);
4043  }
4044 
4045  /* create and add 0 <= z - minact x */
4046  if( !SCIPisZero(scip, minact) )
4047  {
4048  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4049  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
4050  SCIP_CALL( SCIPaddCons(scip, newcons) );
4051  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4052  if( naddconss != NULL )
4053  ++(*naddconss);
4054  }
4055 
4056  /* create and add minact <= sum_j c_j x_j - z + minact x_i */
4057  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4058  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
4059  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4060  if( !SCIPisZero(scip, minact) )
4061  {
4062  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
4063  }
4064  SCIP_CALL( SCIPaddCons(scip, newcons) );
4065  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4066  if( naddconss != NULL )
4067  ++(*naddconss);
4068 
4069  /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4070  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4071  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4072  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4073  if( !SCIPisZero(scip, maxact) )
4074  {
4075  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4076  }
4077  SCIP_CALL( SCIPaddCons(scip, newcons) );
4078  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4079  if( naddconss != NULL )
4080  ++(*naddconss);
4081 
4082  /* create variable expression */
4083  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4084 
4085  /* release auxvar */
4086  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4087 
4088  return SCIP_OKAY;
4089 }
4090 
4091 /** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4092 static
4094  SCIP* scip, /**< SCIP data structure */
4095  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4096  SCIP_CONS* cons, /**< constraint */
4097  SCIP_EXPR* sumexpr, /**< expression */
4098  int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4099  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4100  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4101  )
4102 {
4103  SCIP_EXPR** exprs = NULL;
4104  SCIP_VAR** tmpvars = NULL;
4105  SCIP_VAR** vars = NULL;
4106  SCIP_VAR** xs = NULL;
4107  SCIP_VAR** ys = NULL;
4108  SCIP_Real* exprcoefs = NULL;
4109  SCIP_Real* tmpcoefs = NULL;
4110  SCIP_Real* sumcoefs;
4111  SCIP_Bool* isused = NULL;
4112  int* childidxs = NULL;
4113  int* count = NULL;
4114  int nchildren;
4115  int nexprs = 0;
4116  int nterms;
4117  int nvars;
4118  int ntotalvars;
4119  int i;
4120 
4121  assert(sumexpr != NULL);
4122  assert(minterms > 1);
4123  assert(newexpr != NULL);
4124 
4125  *newexpr = NULL;
4126 
4127  /* check whether sumexpr is indeed a sum */
4128  if( !SCIPisExprSum(scip, sumexpr) )
4129  return SCIP_OKAY;
4130 
4131  nchildren = SCIPexprGetNChildren(sumexpr);
4132  sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4133  nvars = SCIPgetNVars(scip);
4134  ntotalvars = SCIPgetNTotalVars(scip);
4135 
4136  /* check whether there are enough terms available */
4137  if( nchildren < minterms )
4138  return SCIP_OKAY;
4139 
4140  /* allocate memory */
4141  SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4142  SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4143  SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4144 
4145  /* collect all bilinear binary product terms */
4146  SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4147 
4148  /* check whether there are enough terms available */
4149  if( nterms < minterms )
4150  goto TERMINATE;
4151 
4152  /* store how often each variable appears in a bilinear binary product */
4153  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
4154  SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4155  SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4156 
4157  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4158  SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4159  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4160  SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4161 
4162  for( i = 0; i < nterms; ++i )
4163  {
4164  int xidx;
4165  int yidx;
4166 
4167  assert(xs[i] != NULL);
4168  assert(ys[i] != NULL);
4169 
4170  xidx = SCIPvarGetIndex(xs[i]);
4171  assert(xidx < ntotalvars);
4172  yidx = SCIPvarGetIndex(ys[i]);
4173  assert(yidx < ntotalvars);
4174 
4175  ++count[xidx];
4176  ++count[yidx];
4177 
4178  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4179  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4180  }
4181 
4182  /* sort variables; don't change order of count array because it depends on problem indices */
4183  {
4184  int* tmpcount;
4185 
4186  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4187  SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4188  SCIPfreeBufferArray(scip, &tmpcount);
4189  }
4190 
4191  for( i = 0; i < nvars; ++i )
4192  {
4193  SCIP_VAR* facvar = vars[i];
4194  int ntmpvars = 0;
4195  int j;
4196 
4197  /* skip candidate if there are not enough terms left */
4198  if( count[SCIPvarGetIndex(vars[i])] < minterms )
4199  continue;
4200 
4201  SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4202 
4203  /* collect variables for x_i * sum_j c_ij x_j */
4204  for( j = 0; j < nterms; ++j )
4205  {
4206  int childidx = childidxs[j];
4207  assert(childidx >= 0 && childidx < nchildren);
4208 
4209  if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4210  {
4211  SCIP_Real coef;
4212  int xidx;
4213  int yidx;
4214 
4215  coef = sumcoefs[childidx];
4216  assert(coef != 0.0);
4217 
4218  /* collect corresponding variable */
4219  tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4220  tmpcoefs[ntmpvars] = coef;
4221  ++ntmpvars;
4222 
4223  /* update counters */
4224  xidx = SCIPvarGetIndex(xs[j]);
4225  assert(xidx < ntotalvars);
4226  yidx = SCIPvarGetIndex(ys[j]);
4227  assert(yidx < ntotalvars);
4228  --count[xidx];
4229  --count[yidx];
4230  assert(count[xidx] >= 0);
4231  assert(count[yidx] >= 0);
4232 
4233  /* mark term to be used */
4234  isused[childidx] = TRUE;
4235  }
4236  }
4237  assert(ntmpvars >= minterms);
4238  assert(SCIPvarGetIndex(facvar) < ntotalvars);
4239  assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4240 
4241  /* create required constraints and store the generated expression */
4242  SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4243  exprcoefs[nexprs] = 1.0;
4244  ++nexprs;
4245  }
4246 
4247  /* factorization was only successful if at least one expression has been generated */
4248  if( nexprs > 0 )
4249  {
4250  int nexprsold = nexprs;
4251 
4252  /* add all children of the sum that have not been used */
4253  for( i = 0; i < nchildren; ++i )
4254  {
4255  if( !isused[i] )
4256  {
4257  exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4258  exprcoefs[nexprs] = sumcoefs[i];
4259  ++nexprs;
4260  }
4261  }
4262 
4263  /* create a new sum expression */
4264  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4265 
4266  /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4267  for( i = 0; i < nexprsold; ++i )
4268  {
4269  SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4270  }
4271  }
4272 
4273 TERMINATE:
4274  /* free memory */
4275  SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4276  SCIPfreeBufferArrayNull(scip, &tmpvars);
4277  SCIPfreeBufferArrayNull(scip, &exprcoefs);
4278  SCIPfreeBufferArrayNull(scip, &exprs);
4279  SCIPfreeBufferArrayNull(scip, &vars);
4280  SCIPfreeBufferArrayNull(scip, &isused);
4281  SCIPfreeBufferArrayNull(scip, &count);
4282  SCIPfreeBufferArray(scip, &childidxs);
4283  SCIPfreeBufferArray(scip, &ys);
4284  SCIPfreeBufferArray(scip, &xs);
4285 
4286  return SCIP_OKAY;
4287 }
4288 
4289 /** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4290 static
4292  SCIP* scip, /**< SCIP data structure */
4293  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4294  SCIP_EXPR* prodexpr, /**< product expression */
4295  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4296  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4297  SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4298  )
4299 {
4300  SCIP_VAR** vars;
4301  SCIP_CONS* cons;
4302  SCIP_Real* coefs;
4303  SCIP_VAR* w;
4304  char* name;
4305  int nchildren;
4306  int i;
4307 
4308  assert(conshdlr != NULL);
4309  assert(prodexpr != NULL);
4310  assert(SCIPisExprProduct(scip, prodexpr));
4311  assert(newexpr != NULL);
4312 
4313  nchildren = SCIPexprGetNChildren(prodexpr);
4314  assert(nchildren >= 2);
4315 
4316  /* memory to store the variables of the variable expressions (+1 for w) and their name */
4317  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4318  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4319  SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4320 
4321  /* prepare the names of the variable and the constraints */
4322  strcpy(name, "binreform");
4323  for( i = 0; i < nchildren; ++i )
4324  {
4325  vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4326  coefs[i] = 1.0;
4327  assert(vars[i] != NULL);
4328  (void) strcat(name, "_");
4329  (void) strcat(name, SCIPvarGetName(vars[i]));
4330  }
4331 
4332  /* create and add variable */
4333  SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4334  SCIP_CALL( SCIPaddVar(scip, w) );
4335  SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4336 
4337  /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4338  if( nchildren == 2 && !empathy4and )
4339  {
4340  SCIP_VAR* x = vars[0];
4341  SCIP_VAR* y = vars[1];
4342 
4343  assert(x != NULL);
4344  assert(y != NULL);
4345  assert(x != y);
4346 
4347  /* create and add x - w >= 0 */
4348  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4349  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4350  SCIP_CALL( SCIPaddCons(scip, cons) );
4351  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4352 
4353  /* create and add y - w >= 0 */
4354  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4355  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4356  SCIP_CALL( SCIPaddCons(scip, cons) );
4357  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4358 
4359  /* create and add x + y - w <= 1 */
4360  vars[2] = w;
4361  coefs[2] = -1.0;
4362  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4363  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4364  SCIP_CALL( SCIPaddCons(scip, cons) );
4365  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4366 
4367  /* update number of added constraints */
4368  if( naddconss != NULL )
4369  *naddconss += 3;
4370  }
4371  else
4372  {
4373  /* create, add, and release AND constraint */
4374  SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4375  SCIP_CALL( SCIPaddCons(scip, cons) );
4376  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4377  SCIPdebugMsg(scip, " create AND constraint\n");
4378 
4379  /* update number of added constraints */
4380  if( naddconss != NULL )
4381  *naddconss += 1;
4382  }
4383 
4384  /* create variable expression */
4385  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4386 
4387  /* release created variable */
4388  SCIP_CALL( SCIPreleaseVar(scip, &w) );
4389 
4390  /* free memory */
4391  SCIPfreeBufferArray(scip, &name);
4392  SCIPfreeBufferArray(scip, &coefs);
4393  SCIPfreeBufferArray(scip, &vars);
4394 
4395  return SCIP_OKAY;
4396 }
4397 
4398 /** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4399 static
4401  SCIP* scip, /**< SCIP data structure */
4402  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4403  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4404  SCIP_EXPR* prodexpr, /**< product expression */
4405  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4406  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4407  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4408  )
4409 {
4410  SCIP_CONSHDLRDATA* conshdlrdata;
4411  int nchildren;
4412 
4413  assert(prodexpr != NULL);
4414  assert(newexpr != NULL);
4415 
4416  *newexpr = NULL;
4417 
4418  /* only consider products of binary variables */
4419  if( !isBinaryProduct(scip, prodexpr) )
4420  return SCIP_OKAY;
4421 
4422  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4423  assert(conshdlrdata != NULL);
4424  nchildren = SCIPexprGetNChildren(prodexpr);
4425  assert(nchildren >= 2);
4426 
4427  /* check whether there is already an expression that represents the product */
4428  if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4429  {
4430  *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4431  assert(*newexpr != NULL);
4432 
4433  /* capture expression */
4434  SCIPcaptureExpr(*newexpr);
4435  }
4436  else
4437  {
4438  SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4439 
4440  if( nchildren == 2 )
4441  {
4442  SCIP_CLIQUE** xcliques;
4443  SCIP_VAR* x;
4444  SCIP_VAR* y;
4445  SCIP_Bool found_clique = FALSE;
4446  int c;
4447 
4448  /* get variables from the product expression */
4449  x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4450  assert(x != NULL);
4451  y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4452  assert(y != NULL);
4453  assert(x != y);
4454 
4455  /* first try to find a clique containing both variables */
4456  xcliques = SCIPvarGetCliques(x, TRUE);
4457 
4458  /* look in cliques containing x */
4459  for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4460  {
4461  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4462  {
4463  /* create zero value expression */
4464  SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4465 
4466  if( nchgcoefs != NULL )
4467  *nchgcoefs += 1;
4468 
4469  found_clique = TRUE;
4470  break;
4471  }
4472 
4473  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4474  {
4475  /* create variable expression for x */
4476  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4477 
4478  if( nchgcoefs != NULL )
4479  *nchgcoefs += 2;
4480 
4481  found_clique = TRUE;
4482  break;
4483  }
4484  }
4485 
4486  if( !found_clique )
4487  {
4488  xcliques = SCIPvarGetCliques(x, FALSE);
4489 
4490  /* look in cliques containing complement of x */
4491  for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4492  {
4493  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4494  {
4495  /* create variable expression for y */
4496  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4497 
4498  if( nchgcoefs != NULL )
4499  *nchgcoefs += 1;
4500 
4501  found_clique = TRUE;
4502  break;
4503  }
4504 
4505  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4506  {
4507  /* create sum expression */
4508  SCIP_EXPR* sum_children[2];
4509  SCIP_Real sum_coefs[2];
4510  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4511  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4512  sum_coefs[0] = 1.0;
4513  sum_coefs[1] = 1.0;
4514  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4515 
4516  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4517  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4518 
4519  if( nchgcoefs != NULL )
4520  *nchgcoefs += 3;
4521 
4522  found_clique = TRUE;
4523  break;
4524  }
4525  }
4526  }
4527 
4528  /* if the variables are not in a clique, do standard linearization */
4529  if( !found_clique )
4530  {
4531  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4532  }
4533  }
4534  else
4535  {
4536  /* linearize binary product using an AND constraint because nchildren > 2 */
4537  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4538  }
4539 
4540  /* hash variable expression */
4541  SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4542  }
4543 
4544  return SCIP_OKAY;
4545 }
4546 
4547 /** helper function to replace binary products in a given constraint */
4548 static
4550  SCIP* scip, /**< SCIP data structure */
4551  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4552  SCIP_CONS* cons, /**< constraint */
4553  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4554  SCIP_EXPRITER* it, /**< expression iterator */
4555  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4556  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4557  )
4558 {
4559  SCIP_CONSHDLRDATA* conshdlrdata;
4560  SCIP_CONSDATA* consdata;
4561  SCIP_EXPR* expr;
4562 
4563  assert(conshdlr != NULL);
4564  assert(cons != NULL);
4565  assert(exprmap != NULL);
4566  assert(it != NULL);
4567 
4568  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4569  assert(conshdlrdata != NULL);
4570 
4571  consdata = SCIPconsGetData(cons);
4572  assert(consdata != NULL);
4573  assert(consdata->expr != NULL);
4574 
4575  SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4576 
4577  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4578  {
4579  SCIP_EXPR* newexpr = NULL;
4580  SCIP_EXPR* childexpr;
4581  int childexpridx;
4582 
4583  childexpridx = SCIPexpriterGetChildIdxDFS(it);
4584  assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4585  childexpr = SCIPexpriterGetChildExprDFS(it);
4586  assert(childexpr != NULL);
4587 
4588  /* try to factorize variables in a sum expression that contains several products of binary variables */
4589  if( conshdlrdata->reformbinprodsfac > 1 )
4590  {
4591  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4592  }
4593 
4594  /* try to create an expression that represents a product of binary variables */
4595  if( newexpr == NULL )
4596  {
4597  SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4598  }
4599 
4600  if( newexpr != NULL )
4601  {
4602  assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4603 
4604  /* replace product expression */
4605  SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4606 
4607  /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4608  SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4609 
4610  /* mark the constraint to not be simplified anymore */
4611  consdata->issimplified = FALSE;
4612  }
4613  }
4614 
4615  return SCIP_OKAY;
4616 }
4617 
4618 /** reformulates products of binary variables during presolving in the following way:
4619  *
4620  * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4621  * 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}:
4622  * \f[
4623  * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4624  * \f]
4625  *
4626  * 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$.
4627  * These cliques allow for a better reformulation. There are four cases:
4628  *
4629  * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4630  * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4631  * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4632  * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4633  *
4634  * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4635  *
4636  * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4637  * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4638  * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4639  * Such a lower sum is reformulated with only one extra variable w_i:
4640  * \f{align}{
4641  * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4642  * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4643  * \text{minact}\, x_i & \leq w_i, \\
4644  * w_i &\leq \text{maxact}\, x_i, \\
4645  * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4646  * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4647  * \f}
4648  * 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
4649  * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4650  * of terms are prioritized.
4651  */
4652 static
4654  SCIP* scip, /**< SCIP data structure */
4655  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4656  SCIP_CONS** conss, /**< constraints */
4657  int nconss, /**< total number of constraints */
4658  int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4659  int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4660  )
4661 {
4662  SCIP_CONSHDLRDATA* conshdlrdata;
4663  SCIP_HASHMAP* exprmap;
4664  SCIP_EXPRITER* it;
4665  int c;
4666 
4667  assert(conshdlr != NULL);
4668 
4669  /* no nonlinear constraints or binary variables -> skip */
4670  if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4671  return SCIP_OKAY;
4672  assert(conss != NULL);
4673 
4674  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4675  assert(conshdlrdata != NULL);
4676 
4677  /* create expression hash map */
4678  SCIP_CALL( SCIPhashmapCreate(&exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
4679 
4680  /* create expression iterator */
4681  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4684 
4685  SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4686 
4687  for( c = 0; c < nconss; ++c )
4688  {
4689  SCIP_CONSDATA* consdata;
4690  SCIP_EXPR* newexpr = NULL;
4691 
4692  assert(conss[c] != NULL);
4693 
4694  consdata = SCIPconsGetData(conss[c]);
4695  assert(consdata != NULL);
4696 
4697  /* try to reformulate the root expression */
4698  if( conshdlrdata->reformbinprodsfac > 1 )
4699  {
4700  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4701  }
4702 
4703  /* release the root node if another expression has been found */
4704  if( newexpr != NULL )
4705  {
4706  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4707  consdata->expr = newexpr;
4708 
4709  /* mark constraint to be not simplified anymore */
4710  consdata->issimplified = FALSE;
4711  }
4712 
4713  /* replace each product of binary variables separately */
4714  SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4715  }
4716 
4717  /* free memory */
4718  SCIPhashmapFree(&exprmap);
4719  SCIPfreeExpriter(&it);
4720 
4721  return SCIP_OKAY;
4722 }
4723 
4724 /** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4725  *
4726  * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4727  * Then scale by -1 if
4728  * - \f$n_+ < n_-\f$, or
4729  * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4730  */
4731 static
4733  SCIP* scip, /**< SCIP data structure */
4734  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4735  SCIP_CONS* cons, /**< nonlinear constraint */
4736  SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4737  )
4738 {
4739  SCIP_CONSDATA* consdata;
4740  int i;
4741 
4742  assert(cons != NULL);
4743 
4744  consdata = SCIPconsGetData(cons);
4745  assert(consdata != NULL);
4746 
4747  if( SCIPisExprSum(scip, consdata->expr) )
4748  {
4749  SCIP_Real* coefs;
4750  SCIP_Real constant;
4751  int nchildren;
4752  int counter = 0;
4753 
4754  coefs = SCIPgetCoefsExprSum(consdata->expr);
4755  constant = SCIPgetConstantExprSum(consdata->expr);
4756  nchildren = SCIPexprGetNChildren(consdata->expr);
4757 
4758  /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4759  if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4760  {
4761  SCIP_EXPR* expr;
4762  expr = consdata->expr;
4763 
4764  consdata->expr = SCIPexprGetChildren(expr)[0];
4765  assert(!SCIPisExprSum(scip, consdata->expr));
4766 
4767  SCIPcaptureExpr(consdata->expr);
4768 
4769  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4770  consdata->lhs = -consdata->lhs;
4771  consdata->rhs = -consdata->rhs;
4772 
4773  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4774  *changed = TRUE;
4775  return SCIP_OKAY;
4776  }
4777 
4778  /* compute n_+ - n_i */
4779  for( i = 0; i < nchildren; ++i )
4780  counter += coefs[i] > 0 ? 1 : -1;
4781 
4782  if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4783  {
4784  SCIP_EXPR* expr;
4785  SCIP_Real* newcoefs;
4786 
4787  /* allocate memory */
4788  SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4789 
4790  for( i = 0; i < nchildren; ++i )
4791  newcoefs[i] = -coefs[i];
4792 
4793  /* create a new sum expression */
4794  SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4795 
4796  /* replace expression in constraint data and scale sides */
4797  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4798  consdata->expr = expr;
4799  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4800  consdata->lhs = -consdata->lhs;
4801  consdata->rhs = -consdata->rhs;
4802 
4803  /* free memory */
4804  SCIPfreeBufferArray(scip, &newcoefs);
4805 
4806  *changed = TRUE;
4807  }
4808  }
4809 
4810  return SCIP_OKAY;
4811 }
4812 
4813 /** forbid multiaggrations of variables that appear nonlinear in constraints */
4814 static
4816  SCIP* scip, /**< SCIP data structure */
4817  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4818  SCIP_CONS** conss, /**< constraints */
4819  int nconss /**< number of constraints */
4820  )
4821 {
4822  SCIP_EXPRITER* it;
4823  SCIP_CONSDATA* consdata;
4824  SCIP_EXPR* expr;
4825  int c;
4826 
4827  assert(scip != NULL);
4828  assert(conshdlr != NULL);
4829 
4830  if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4831  return SCIP_OKAY;
4832 
4833  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4835 
4836  for( c = 0; c < nconss; ++c )
4837  {
4838  consdata = SCIPconsGetData(conss[c]);
4839  assert(consdata != NULL);
4840 
4841  /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4842  * i.e., skip children of sum that are variables
4843  */
4844  if( SCIPisExprSum(scip, consdata->expr) )
4845  {
4846  int i;
4847  SCIP_EXPR* child;
4848  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4849  {
4850  child = SCIPexprGetChildren(consdata->expr)[i];
4851 
4852  /* skip variable expression, as they correspond to a linear term */
4853  if( SCIPisExprVar(scip, child) )
4854  continue;
4855 
4856  for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4857  if( SCIPisExprVar(scip, expr) )
4858  {
4860  }
4861  }
4862  }
4863  else
4864  {
4865  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4866  if( SCIPisExprVar(scip, expr) )
4867  {
4869  }
4870  }
4871  }
4872 
4873  SCIPfreeExpriter(&it);
4874 
4875  return SCIP_OKAY;
4876 }
4877 
4878 /** simplifies expressions and replaces common subexpressions for a set of constraints
4879  * @todo put the constant to the constraint sides
4880  */
4881 static
4883  SCIP* scip, /**< SCIP data structure */
4884  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4885  SCIP_CONS** conss, /**< constraints */
4886  int nconss, /**< total number of constraints */
4887  SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4888  SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4889  int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4890  int* naddconss, /**< counter to add number of added constraints, or NULL */
4891  int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4892  )
4893 {
4894  SCIP_CONSHDLRDATA* conshdlrdata;
4895  SCIP_CONSDATA* consdata;
4896  int* nlockspos;
4897  int* nlocksneg;
4898  SCIP_Bool havechange;
4899  int i;
4900 
4901  assert(scip != NULL);
4902  assert(conshdlr != NULL);
4903  assert(conss != NULL);
4904  assert(nconss > 0);
4905  assert(infeasible != NULL);
4906 
4907  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4908  assert(conshdlrdata != NULL);
4909 
4910  /* update number of canonicalize calls */
4911  ++(conshdlrdata->ncanonicalizecalls);
4912 
4913  SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4914 
4915  *infeasible = FALSE;
4916 
4917  /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4918  havechange = conshdlrdata->ncanonicalizecalls == 1;
4919 
4920  /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4921  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4922 
4923  /* allocate memory for storing locks of each constraint */
4924  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4925  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4926 
4927  /* unlock all constraints */
4928  for( i = 0; i < nconss; ++i )
4929  {
4930  assert(conss[i] != NULL);
4931 
4932  consdata = SCIPconsGetData(conss[i]);
4933  assert(consdata != NULL);
4934 
4935  /* remember locks */
4936  nlockspos[i] = consdata->nlockspos;
4937  nlocksneg[i] = consdata->nlocksneg;
4938 
4939  /* remove locks */
4940  SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4941  assert(consdata->nlockspos == 0);
4942  assert(consdata->nlocksneg == 0);
4943  }
4944 
4945 #ifndef NDEBUG
4946  /* check whether all locks of each expression have been removed */
4947  for( i = 0; i < nconss; ++i )
4948  {
4949  SCIP_EXPR* expr;
4950  SCIP_EXPRITER* it;
4951 
4952  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4953 
4954  consdata = SCIPconsGetData(conss[i]);
4955  assert(consdata != NULL);
4956 
4957  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_RTOPOLOGIC, TRUE) );
4958  for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4959  {
4960  assert(expr != NULL);
4961  assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4962  assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4963  }
4964  SCIPfreeExpriter(&it);
4965  }
4966 #endif
4967 
4968  /* reformulate products of binary variables */
4969  if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4970  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4971  {
4972  int tmpnaddconss = 0;
4973  int tmpnchgcoefs = 0;
4974 
4975  /* call this function before simplification because expressions might not be simplified after reformulating
4976  * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4977  */
4978  SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4979 
4980  /* update counters */
4981  if( naddconss != NULL )
4982  *naddconss += tmpnaddconss;
4983  if( nchgcoefs != NULL )
4984  *nchgcoefs += tmpnchgcoefs;
4985 
4986  /* check whether at least one expression has changed */
4987  if( tmpnaddconss + tmpnchgcoefs > 0 )
4988  havechange = TRUE;
4989  }
4990 
4991  for( i = 0; i < nconss; ++i )
4992  {
4993  consdata = SCIPconsGetData(conss[i]);
4994  assert(consdata != NULL);
4995 
4996  /* call simplify for each expression */
4997  if( !consdata->issimplified && consdata->expr != NULL )
4998  {
4999  SCIP_EXPR* simplified;
5000  SCIP_Bool changed;
5001 
5002  changed = FALSE;
5003  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
5004  consdata->issimplified = TRUE;
5005 
5006  if( changed )
5007  havechange = TRUE;
5008 
5009  /* 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").
5010  * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
5011  */
5012  if( simplified != consdata->expr )
5013  {
5014  assert(changed);
5015 
5016  /* release old expression */
5017  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
5018 
5019  /* store simplified expression */
5020  consdata->expr = simplified;
5021  }
5022  else
5023  {
5024  /* The simplify captures simplified in any case, also if nothing has changed.
5025  * Therefore, we have to release it here.
5026  */
5027  SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
5028  }
5029 
5030  if( *infeasible )
5031  break;
5032 
5033  /* scale constraint sides */
5034  SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
5035 
5036  if( changed )
5037  havechange = TRUE;
5038 
5039  /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
5040  if( SCIPisExprValue(scip, consdata->expr) )
5041  {
5042  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5043  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5044  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5045  {
5046  SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5047  SCIPdebugPrintCons(scip, conss[i], NULL);
5048  *infeasible = TRUE;
5049  break;
5050  }
5051  else
5052  {
5053  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5054  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5055  if( ndelconss != NULL )
5056  ++*ndelconss;
5057  havechange = TRUE;
5058  }
5059  }
5060  }
5061  }
5062 
5063  /* replace common subexpressions */
5064  if( havechange && !*infeasible )
5065  {
5066  SCIP_CONS** consssorted;
5067  SCIP_EXPR** rootexprs;
5068  SCIP_Bool replacedroot;
5069 
5070  SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5071  for( i = 0; i < nconss; ++i )
5072  rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5073 
5074  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5075 
5076  /* update pointer to root expr in constraints, if any has changed
5077  * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5078  */
5079  if( replacedroot )
5080  for( i = 0; i < nconss; ++i )
5081  SCIPconsGetData(conss[i])->expr = rootexprs[i];
5082 
5083  SCIPfreeBufferArray(scip, &rootexprs);
5084 
5085  /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5086  * been changed after simplification; now we completely recollect all variable expression and variable events
5087  */
5088 
5089  /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5090  * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5091  */
5092  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5093  SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5094 
5095  for( i = nconss-1; i >= 0; --i )
5096  {
5097  assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5098  if( SCIPconsIsDeleted(consssorted[i]) )
5099  continue;
5100 
5101  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5102  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5103  }
5104  for( i = 0; i < nconss; ++i )
5105  {
5106  if( SCIPconsIsDeleted(consssorted[i]) )
5107  continue;
5108 
5109  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5110  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5111  }
5112 
5113  SCIPfreeBufferArray(scip, &consssorted);
5114 
5115  /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5116  * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5117  * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5118  */
5119  SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5120  }
5121 
5122  /* restore locks */
5123  for( i = 0; i < nconss; ++i )
5124  {
5125  if( SCIPconsIsDeleted(conss[i]) )
5126  continue;
5127 
5128  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5129  }
5130 
5131  /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5132  * TODO can we skip this in presoltiming fast?
5133  */
5134  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5135  {
5136  /* reset one of the number of detections counter to count only current presolving round */
5137  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5138  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5139 
5140  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5141  }
5142 
5143  /* free allocated memory */
5144  SCIPfreeBufferArray(scip, &nlocksneg);
5145  SCIPfreeBufferArray(scip, &nlockspos);
5146 
5147  SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5148 
5149  return SCIP_OKAY;
5150 }
5151 
5152 /** merges constraints that have the same root expression */
5153 static
5155  SCIP* scip, /**< SCIP data structure */
5156  SCIP_CONS** conss, /**< constraints to process */
5157  int nconss, /**< number of constraints */
5158  SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5159  )
5160 {
5161  SCIP_HASHMAP* expr2cons;
5162  SCIP_Bool* updatelocks;
5163  int* nlockspos;
5164  int* nlocksneg;
5165  int c;
5166 
5167  assert(success != NULL);
5168 
5169  *success = FALSE;
5170 
5171  /* not enough constraints available */
5172  if( nconss <= 1 )
5173  return SCIP_OKAY;
5174 
5175  SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5176  SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5177  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5178  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5179 
5180  for( c = 0; c < nconss; ++c )
5181  {
5182  SCIP_CONSDATA* consdata;
5183 
5184  /* ignore deleted constraints */
5185  if( SCIPconsIsDeleted(conss[c]) )
5186  continue;
5187 
5188  consdata = SCIPconsGetData(conss[c]);
5189  assert(consdata != NULL);
5190 
5191  /* add expression to the hash map if not seen so far */
5192  if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5193  {
5194  SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5195  }
5196  else
5197  {
5198  SCIP_CONSDATA* imgconsdata;
5199  int idx;
5200 
5201  idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5202  assert(idx >= 0 && idx < nconss);
5203 
5204  imgconsdata = SCIPconsGetData(conss[idx]);
5205  assert(imgconsdata != NULL);
5206  assert(imgconsdata->expr == consdata->expr);
5207 
5208  SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5209  SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5210 
5211  /* check whether locks need to be updated */
5212  if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5213  || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5214  {
5215  nlockspos[idx] = imgconsdata->nlockspos;
5216  nlocksneg[idx] = imgconsdata->nlocksneg;
5217  SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5218  updatelocks[idx] = TRUE;
5219  }
5220 
5221  /* update constraint sides */
5222  imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5223  imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5224 
5225  /* delete constraint */
5226  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5227  *success = TRUE;
5228  }
5229  }
5230 
5231  /* restore locks of updated constraints */
5232  if( *success )
5233  {
5234  for( c = 0; c < nconss; ++c )
5235  {
5236  if( updatelocks[c] )
5237  {
5238  SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5239  }
5240  }
5241  }
5242 
5243  /* free memory */
5244  SCIPfreeBufferArray(scip, &nlocksneg);
5245  SCIPfreeBufferArray(scip, &nlockspos);
5246  SCIPfreeBufferArray(scip, &updatelocks);
5247  SCIPhashmapFree(&expr2cons);
5248 
5249  return SCIP_OKAY;
5250 }
5251 
5252 /** interval evaluation of variables as used in redundancy check
5253  *
5254  * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5255  */
5256 static
5257 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5258 { /*lint --e{715}*/
5259  SCIP_CONSHDLRDATA* conshdlrdata;
5260  SCIP_INTERVAL interval;
5261  SCIP_Real lb;
5262  SCIP_Real ub;
5263 
5264  assert(scip != NULL);
5265  assert(var != NULL);
5266 
5267  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5268  assert(conshdlrdata != NULL);
5269 
5270  if( conshdlrdata->globalbounds )
5271  {
5272  lb = SCIPvarGetLbGlobal(var);
5273  ub = SCIPvarGetUbGlobal(var);
5274  }
5275  else
5276  {
5277  lb = SCIPvarGetLbLocal(var);
5278  ub = SCIPvarGetUbLocal(var);
5279  }
5280  assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5281 
5282  /* relax variable bounds, if there are bounds and variable is not fixed
5283  * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5284  */
5285  if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5286  {
5287  if( !SCIPisInfinity(scip, -lb) )
5288  lb -= SCIPfeastol(scip);
5289 
5290  if( !SCIPisInfinity(scip, ub) )
5291  ub += SCIPfeastol(scip);
5292  }
5293 
5294  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5295  lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
5297  assert(lb <= ub);
5298 
5299  SCIPintervalSetBounds(&interval, lb, ub);
5300 
5301  return interval;
5302 }
5303 
5304 /** removes constraints that are always feasible or very simple
5305  *
5306  * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5307  * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5308  * might violate variable bounds by up to feastol, too.
5309  * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5310  *
5311  * Also removes constraints of the form lhs &le; variable &le; rhs.
5312  *
5313  * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5314  *
5315  * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5316  * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5317  * would appear as if the constraint is redundant.
5318  */
5319 static
5321  SCIP* scip, /**< SCIP data structure */
5322  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5323  SCIP_CONS** conss, /**< constraints to propagate */
5324  int nconss, /**< total number of constraints */
5325  SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5326  int* ndelconss, /**< buffer to add the number of deleted constraints */
5327  int* nchgbds /**< buffer to add the number of variable bound tightenings */
5328  )
5329 {
5330  SCIP_CONSHDLRDATA* conshdlrdata;
5331  SCIP_CONSDATA* consdata;
5332  SCIP_INTERVAL activity;
5333  SCIP_INTERVAL sides;
5334  int i;
5335 
5336  assert(scip != NULL);
5337  assert(conshdlr != NULL);
5338  assert(conss != NULL);
5339  assert(nconss >= 0);
5340  assert(cutoff != NULL);
5341  assert(ndelconss != NULL);
5342  assert(nchgbds != NULL);
5343 
5344  /* no constraints to check */
5345  if( nconss == 0 )
5346  return SCIP_OKAY;
5347 
5348  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5349  assert(conshdlrdata != NULL);
5350 
5351  /* increase curboundstag and set lastvaractivitymethodchange
5352  * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5353  * for the redundancy check differently than for domain propagation
5354  * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5355  */
5356  ++conshdlrdata->curboundstag;
5357  assert(conshdlrdata->curboundstag > 0);
5358  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5359  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5360  conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5361 
5362  SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5363 
5364  *cutoff = FALSE;
5365  for( i = 0; i < nconss; ++i )
5366  {
5367  if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5368  continue;
5369 
5370  consdata = SCIPconsGetData(conss[i]);
5371  assert(consdata != NULL);
5372 
5373  /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5374  if( SCIPisExprValue(scip, consdata->expr) )
5375  {
5376  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5377 
5378  if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5379  (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5380  {
5381  SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5382  *cutoff = TRUE;
5383 
5384  goto TERMINATE;
5385  }
5386 
5387  SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5388 
5389  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5390  ++*ndelconss;
5391 
5392  continue;
5393  }
5394 
5395  /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5396  if( SCIPisExprVar(scip, consdata->expr) )
5397  {
5398  SCIP_VAR* var;
5399  SCIP_Bool tightened;
5400 
5401  var = SCIPgetVarExprVar(consdata->expr);
5402  assert(var != NULL);
5403 
5404  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);
5405 
5406  /* ensure that variable bounds are within constraint sides */
5407  if( !SCIPisInfinity(scip, -consdata->lhs) )
5408  {
5409  SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5410 
5411  if( tightened )
5412  ++*nchgbds;
5413 
5414  if( *cutoff )
5415  goto TERMINATE;
5416  }
5417 
5418  if( !SCIPisInfinity(scip, consdata->rhs) )
5419  {
5420  SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5421 
5422  if( tightened )
5423  ++*nchgbds;
5424 
5425  if( *cutoff )
5426  goto TERMINATE;
5427  }
5428 
5429  /* delete the (now) redundant constraint locally */
5430  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5431  ++*ndelconss;
5432 
5433  continue;
5434  }
5435 
5436  /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5437  * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5438  * variable bounds by up to feastol
5439  * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5440  */
5441  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5442  SCIPdebugPrintCons(scip, conss[i], NULL);
5443 
5444  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5445  assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5446 
5447  /* it is unlikely that we detect infeasibility by doing forward propagation */
5448  if( *cutoff )
5449  {
5450  SCIPdebugMsg(scip, " -> cutoff\n");
5451  goto TERMINATE;
5452  }
5453 
5454  assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5455  activity = SCIPexprGetActivity(consdata->expr);
5456 
5457  /* relax sides by feastol
5458  * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5459  */
5460  SCIPintervalSetBounds(&sides,
5461  SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5462  SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5463 
5464  if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5465  {
5466  SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5467 
5468  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5469  ++*ndelconss;
5470 
5471  continue;
5472  }
5473 
5474  SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5475  }
5476 
5477 TERMINATE:
5478  /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5479  ++conshdlrdata->curboundstag;
5480  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5481  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5482  conshdlrdata->intevalvar = intEvalVarBoundTightening;
5483 
5484  return SCIP_OKAY;
5485 }
5486 
5487 /** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5488 static
5490  SCIP* scip, /**< SCIP data structure */
5491  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5492  SCIP_CONS* cons, /**< source constraint to try to convert */
5493  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5494  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5495  int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5496  )
5497 {
5498  SCIP_CONSHDLRDATA* conshdlrdata;
5499  SCIP_CONSDATA* consdata;
5500  SCIP_CONS** upgdconss;
5501  int upgdconsssize;
5502  int nupgdconss_;
5503  int i;
5504 
5505  assert(scip != NULL);
5506  assert(conshdlr != NULL);
5507  assert(cons != NULL);
5508  assert(!SCIPconsIsModifiable(cons));
5509  assert(upgraded != NULL);
5510  assert(nupgdconss != NULL);
5511  assert(naddconss != NULL);
5512 
5513  *upgraded = FALSE;
5514 
5515  nupgdconss_ = 0;
5516 
5517  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5518  assert(conshdlrdata != NULL);
5519 
5520  /* if there are no upgrade methods, we can stop */
5521  if( conshdlrdata->nconsupgrades == 0 )
5522  return SCIP_OKAY;
5523 
5524  upgdconsssize = 2;
5525  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5526 
5527  /* call the upgrading methods */
5528  SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5529  SCIPdebugPrintCons(scip, cons, NULL);
5530 
5531  consdata = SCIPconsGetData(cons);
5532  assert(consdata != NULL);
5533 
5534  /* try all upgrading methods in priority order in case the upgrading step is enable */
5535  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5536  {
5537  if( !conshdlrdata->consupgrades[i]->active )
5538  continue;
5539 
5540  assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5541 
5542  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5543 
5544  while( nupgdconss_ < 0 )
5545  {
5546  /* upgrade function requires more memory: resize upgdconss and call again */
5547  assert(-nupgdconss_ > upgdconsssize);
5548  upgdconsssize = -nupgdconss_;
5549  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5550 
5551  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5552 
5553  assert(nupgdconss_ != 0);
5554  }
5555 
5556  if( nupgdconss_ > 0 )
5557  {
5558  /* got upgrade */
5559  int j;
5560 
5561  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5562 
5563  /* add the upgraded constraints to the problem and forget them */
5564  for( j = 0; j < nupgdconss_; ++j )
5565  {
5566  SCIPdebugMsgPrint(scip, "\t");
5567  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5568 
5569  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5570  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5571  }
5572 
5573  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5574  *nupgdconss += 1;
5575  *naddconss += nupgdconss_ - 1;
5576  *upgraded = TRUE;
5577 
5578  /* delete upgraded constraint */
5579  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5580  SCIP_CALL( SCIPdelCons(scip, cons) );
5581 
5582  break;
5583  }
5584  }
5585 
5586  SCIPfreeBufferArray(scip, &upgdconss);
5587 
5588  return SCIP_OKAY;
5589 }
5590 
5591 /** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5592  * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5593  * variable bounds, and is not binary
5594  */
5595 static
5597  SCIP* scip, /**< SCIP data structure */
5598  SCIP_EXPR* expr /**< variable expression */
5599  )
5600 {
5601  SCIP_VAR* var;
5602  SCIP_EXPR_OWNERDATA* ownerdata;
5603 
5604  assert(SCIPisExprVar(scip, expr));
5605 
5606  var = SCIPgetVarExprVar(expr);
5607  assert(var != NULL);
5608 
5609  ownerdata = SCIPexprGetOwnerData(expr);
5610  assert(ownerdata != NULL);
5611 
5612  return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5613  && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5614  && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5615  && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5617  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5618 }
5619 
5620 /** removes all variable expressions that are contained in a given expression from a hash map */
5621 static
5623  SCIP* scip, /**< SCIP data structure */
5624  SCIP_EXPR* expr, /**< expression */
5625  SCIP_EXPRITER* it, /**< expression iterator */
5626  SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5627  )
5628 {
5629  SCIP_EXPR* e;
5630 
5631  for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5632  {
5633  if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5634  {
5635  SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5636  }
5637  }
5638 
5639  return SCIP_OKAY;
5640 }
5641 
5642 /** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5643  * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5644  *
5645  * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5646  * Otherwise, a bound disjunction constraint is added.
5647  *
5648  * @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
5649  * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5650  * 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
5651  * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5652  * @todo reduction should also be applicable if variable appears in the objective with the right sign (sign such that opt is at boundary)
5653  */
5654 static
5656  SCIP* scip, /**< SCIP data structure */
5657  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5658  SCIP_CONS* cons, /**< nonlinear constraint */
5659  int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5660  int* naddconss, /**< pointer to store the total number of added constraints */
5661  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5662  )
5663 {
5664  SCIP_CONSHDLRDATA* conshdlrdata;
5665  SCIP_CONSDATA* consdata;
5666  SCIP_EXPR** singlelocked;
5667  SCIP_HASHMAP* exprcands;
5668  SCIP_Bool hasbounddisj;
5669  SCIP_Bool haslhs;
5670  SCIP_Bool hasrhs;
5671  int nsinglelocked = 0;
5672  int i;
5673 
5674  assert(conshdlr != NULL);
5675  assert(cons != NULL);
5676  assert(nchgvartypes != NULL);
5677  assert(naddconss != NULL);
5678  assert(infeasible != NULL);
5679 
5680  *nchgvartypes = 0;
5681  *naddconss = 0;
5682  *infeasible = FALSE;
5683 
5684  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5685  assert(conshdlrdata != NULL);
5686  consdata = SCIPconsGetData(cons);
5687  assert(consdata != NULL);
5688 
5689  /* only consider constraints with one finite side */
5690  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5691  return SCIP_OKAY;
5692 
5693  /* only consider sum expressions */
5694  if( !SCIPisExprSum(scip, consdata->expr) )
5695  return SCIP_OKAY;
5696 
5697  /* remember which side is finite */
5698  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5699  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5700 
5701  /* allocate memory */
5702  SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5703  SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5704 
5705  /* check all variable expressions for single locked variables */
5706  for( i = 0; i < consdata->nvarexprs; ++i )
5707  {
5708  assert(consdata->varexprs[i] != NULL);
5709 
5710  if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5711  {
5712  SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5713  singlelocked[nsinglelocked++] = consdata->varexprs[i];
5714  }
5715  }
5716  SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5717 
5718  if( nsinglelocked > 0 )
5719  {
5720  SCIP_EXPR** children;
5721  SCIP_EXPRITER* it;
5722  int nchildren;
5723 
5724  children = SCIPexprGetChildren(consdata->expr);
5725  nchildren = SCIPexprGetNChildren(consdata->expr);
5726 
5727  /* create iterator */
5728  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
5731 
5732  for( i = 0; i < nchildren; ++i )
5733  {
5734  SCIP_EXPR* child;
5735  SCIP_Real coef;
5736 
5737  child = children[i];
5738  assert(child != NULL);
5739  coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5740 
5741  /* ignore linear terms */
5742  if( SCIPisExprVar(scip, child) )
5743  continue;
5744 
5745  /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5746  * expression that represents f_j and remove each variable expression from exprcands
5747  */
5748  else if( SCIPisExprProduct(scip, child) )
5749  {
5750  int j;
5751 
5752  for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5753  {
5754  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5755 
5756  if( !SCIPisExprVar(scip, grandchild) )
5757  {
5758  /* mark all variable expressions that are contained in the expression */
5759  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5760  }
5761  }
5762  }
5763  /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5764  * for an integer k >= 1
5765  */
5766  else if( SCIPisExprPower(scip, child) )
5767  {
5768  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5769  SCIP_Real exponent = SCIPgetExponentExprPow(child);
5770  SCIP_Bool valid;
5771 
5772  /* check for even integral exponent */
5773  valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5774 
5775  if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5776  {
5777  /* mark all variable expressions that are contained in the expression */
5778  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5779  }
5780  }
5781  /* all other cases cannot be handled */
5782  else
5783  {
5784  /* mark all variable expressions that are contained in the expression */
5785  SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5786  }
5787  }
5788 
5789  /* free expression iterator */
5790  SCIPfreeExpriter(&it);
5791  }
5792 
5793  /* check whether the bound disjunction constraint handler is available */
5794  hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5795 
5796  /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5797  for( i = 0; i < nsinglelocked; ++i )
5798  {
5799  /* only consider expressions that are still contained in the exprcands map */
5800  if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5801  {
5802  SCIP_CONS* newcons;
5803  SCIP_VAR* vars[2];
5804  SCIP_BOUNDTYPE boundtypes[2];
5805  SCIP_Real bounds[2];
5806  char name[SCIP_MAXSTRLEN];
5807  SCIP_VAR* var;
5808 
5809  var = SCIPgetVarExprVar(singlelocked[i]);
5810  assert(var != NULL);
5811  SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5813 
5814  /* try to change the variable type to binary */
5815  if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5816  {
5817  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5818  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5819  ++(*nchgvartypes);
5820 
5821  if( *infeasible )
5822  {
5823  SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5824  break;
5825  }
5826  }
5827  /* add bound disjunction constraint if bounds of the variable are finite */
5828  else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5829  {
5830  vars[0] = var;
5831  vars[1] = var;
5832  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5833  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5834  bounds[0] = SCIPvarGetUbGlobal(var);
5835  bounds[1] = SCIPvarGetLbGlobal(var);
5836 
5837  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5838 
5839  /* create, add, and release bound disjunction constraint */
5840  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5841  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5842  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5843  SCIP_CALL( SCIPaddCons(scip, newcons) );
5844  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5845  ++(*naddconss);
5846  }
5847  }
5848  }
5849 
5850  /* free memory */
5851  SCIPfreeBufferArray(scip, &singlelocked);
5852  SCIPhashmapFree(&exprcands);
5853 
5854  return SCIP_OKAY;
5855 }
5856 
5857 /** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5858 static
5860  SCIP* scip, /**< SCIP data structure */
5861  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5862  SCIP_CONS** conss, /**< nonlinear constraints */
5863  int nconss, /**< total number of nonlinear constraints */
5864  int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5865  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5866  )
5867 {
5868  int c;
5869 
5870  assert(scip != NULL);
5871  assert(conshdlr != NULL);
5872  assert(conss != NULL || nconss == 0);
5873  assert(nchgvartypes != NULL);
5874  assert(infeasible != NULL);
5875 
5876  *infeasible = FALSE;
5877 
5878  /* nothing can be done if there are no binary and integer variables available */
5879  if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5880  return SCIP_OKAY;
5881 
5882  /* no continuous var can be made implicit-integer if there are no continuous variables */
5883  if( SCIPgetNContVars(scip) == 0 )
5884  return SCIP_OKAY;
5885 
5886  for( c = 0; c < nconss; ++c )
5887  {
5888  SCIP_CONSDATA* consdata;
5889  SCIP_EXPR** children;
5890  int nchildren;
5891  SCIP_Real* coefs;
5892  SCIP_EXPR* cand = NULL;
5893  SCIP_Real candcoef = 0.0;
5894  int i;
5895 
5896  assert(conss != NULL && conss[c] != NULL);
5897 
5898  consdata = SCIPconsGetData(conss[c]);
5899  assert(consdata != NULL);
5900 
5901  /* the constraint must be an equality constraint */
5902  if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5903  continue;
5904 
5905  /* the root expression needs to be a sum expression */
5906  if( !SCIPisExprSum(scip, consdata->expr) )
5907  continue;
5908 
5909  children = SCIPexprGetChildren(consdata->expr);
5910  nchildren = SCIPexprGetNChildren(consdata->expr);
5911 
5912  /* the sum expression must have at least two children
5913  * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5914  */
5915  if( nchildren <= 1 )
5916  continue;
5917 
5918  coefs = SCIPgetCoefsExprSum(consdata->expr);
5919 
5920  /* find first continuous variable and get value of its coefficient */
5921  for( i = 0; i < nchildren; ++i )
5922  {
5923  if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5924  continue;
5925 
5926  candcoef = coefs[i];
5927  assert(candcoef != 0.0);
5928 
5929  /* lhs/rhs - constant divided by candcoef must be integral
5930  * if not, break with cand == NULL, so give up
5931  */
5932  if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5933  cand = children[i];
5934 
5935  break;
5936  }
5937 
5938  /* no suitable continuous variable found */
5939  if( cand == NULL )
5940  continue;
5941 
5942  /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5943  for( i = 0; i < nchildren; ++i )
5944  {
5945  if( children[i] == cand )
5946  continue;
5947 
5948  /* child i must be integral */
5949  if( !SCIPexprIsIntegral(children[i]) )
5950  {
5951  cand = NULL;
5952  break;
5953  }
5954 
5955  /* coefficient of child i must be integral if diving by candcoef */
5956  if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5957  {
5958  cand = NULL;
5959  break;
5960  }
5961  }
5962 
5963  if( cand == NULL )
5964  continue;
5965 
5966  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5968 
5969  /* change variable type */
5970  SCIP_CALL( SCIPchgVarType(scip, SCIPgetVarExprVar(cand), SCIP_VARTYPE_IMPLINT, infeasible) );
5971 
5972  if( *infeasible )
5973  return SCIP_OKAY;
5974 
5975  /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5977  }
5978 
5979  return SCIP_OKAY;
5980 }
5981 
5982 /** creates auxiliary variable for a given expression
5983  *
5984  * @note for a variable expression it does nothing
5985  * @note this function can only be called in stage SCIP_STAGE_SOLVING
5986  */
5987 static
5989  SCIP* scip, /**< SCIP data structure */
5990  SCIP_EXPR* expr /**< expression */
5991  )
5992 {
5993  SCIP_EXPR_OWNERDATA* ownerdata;
5994  SCIP_CONSHDLRDATA* conshdlrdata;
5995  SCIP_VARTYPE vartype;
5996  SCIP_INTERVAL activity;
5997  char name[SCIP_MAXSTRLEN];
5998 
5999  assert(scip != NULL);
6000  assert(expr != NULL);
6001 
6002  ownerdata = SCIPexprGetOwnerData(expr);
6003  assert(ownerdata != NULL);
6004  assert(ownerdata->nauxvaruses > 0);
6005 
6006  /* if we already have auxvar, then do nothing */
6007  if( ownerdata->auxvar != NULL )
6008  return SCIP_OKAY;
6009 
6010  /* if expression is a variable-expression, then do nothing */
6011  if( SCIPisExprVar(scip, expr) )
6012  return SCIP_OKAY;
6013 
6014  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
6015  {
6016  SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
6017  return SCIP_INVALIDCALL;
6018  }
6019 
6020  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6021  assert(conshdlrdata != NULL);
6022  assert(conshdlrdata->auxvarid >= 0);
6023 
6024  /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6025  * but it usually indicates a missing simplify
6026  * if we find situations where we need to have an auxvar for a constant, then remove this assert
6027  */
6028  assert(!SCIPisExprValue(scip, expr));
6029 
6030  /* create and capture auxiliary variable */
6031  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6032  ++conshdlrdata->auxvarid;
6033 
6034  /* type of auxiliary variable depends on integrality information of the expression */
6036 
6037  /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6038  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6039  {
6040  activity = SCIPexprGetActivity(expr);
6041  /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6042  * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6043  * and abort in debug mode only
6044  */
6046  {
6047  SCIPABORT();
6049  }
6050  }
6051  else
6053 
6054  /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6055  * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6056  */
6057  if( SCIPgetDepth(scip) == 0 )
6058  {
6059  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
6060  }
6061  else
6062  {
6063  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
6064  }
6065 
6066  /* mark the auxiliary variable to be added for the relaxation only
6067  * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6068  * or to copy the variable to a subscip
6069  */
6070  SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6071 
6072  SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6073 
6074  SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6075 
6076  /* add variable locks in both directions
6077  * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6078  * but then we need to also update the auxvars locks when the expr locks change
6079  */
6080  SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6081 
6082 #ifdef WITH_DEBUG_SOLUTION
6083  if( SCIPdebugIsMainscip(scip) )
6084  {
6085  /* store debug solution value of auxiliary variable
6086  * assumes that expression has been evaluated in debug solution before
6087  */
6088  SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6089  }
6090 #endif
6091 
6092  if( SCIPgetDepth(scip) > 0 )
6093  {
6094  /* initialize local bounds to (locally valid) activity */
6095  SCIP_Bool cutoff;
6096  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6097  assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6098  }
6099 
6100  return SCIP_OKAY;
6101 }
6102 
6103 /** initializes separation for constraint
6104  *
6105  * - ensures that activities are up to date in all expressions
6106  * - creates auxiliary variables where required
6107  * - calls propExprDomains() to possibly tighten auxvar bounds
6108  * - calls separation initialization callback of nlhdlrs
6109  */
6110 static
6112  SCIP* scip, /**< SCIP data structure */
6113  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6114  SCIP_CONS** conss, /**< constraints */
6115  int nconss, /**< number of constraints */
6116  SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6117  )
6118 {
6119  SCIP_CONSDATA* consdata;
6120  SCIP_CONSHDLRDATA* conshdlrdata;
6121  SCIP_EXPRITER* it;
6122  SCIP_EXPR* expr;
6123  SCIP_RESULT result;
6124  SCIP_VAR* auxvar;
6125  int nreductions = 0;
6126  int c, e;
6127 
6128  assert(scip != NULL);
6129  assert(conshdlr != NULL);
6130  assert(conss != NULL || nconss == 0);
6131  assert(nconss >= 0);
6132  assert(infeasible != NULL);
6133 
6134  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6135  assert(conshdlrdata != NULL);
6136 
6137  /* start with new propbounds (just to be sure, should not be needed) */
6138  ++conshdlrdata->curpropboundstag;
6139 
6140  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6142 
6143  /* first ensure activities are up to date and create auxvars */
6144  *infeasible = FALSE;
6145  for( c = 0; c < nconss; ++c )
6146  {
6147  assert(conss != NULL);
6148  assert(conss[c] != NULL);
6149 
6150  consdata = SCIPconsGetData(conss[c]);
6151  assert(consdata != NULL);
6152  assert(consdata->expr != NULL);
6153 
6154 #ifdef WITH_DEBUG_SOLUTION
6155  if( SCIPdebugIsMainscip(scip) )
6156  {
6157  SCIP_SOL* debugsol;
6158 
6159  SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6160 
6161  if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6162  {
6163  /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6164  * in createAuxVar()
6165  */
6166  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6167  }
6168  }
6169 #endif
6170 
6171  /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6172  SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6173 
6174  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6175  {
6176  if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6177  {
6178  SCIP_CALL( createAuxVar(scip, expr) );
6179  }
6180  }
6181 
6182  auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6183  if( auxvar != NULL )
6184  {
6185  SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6186  SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6187  /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6188  SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6189  if( *infeasible )
6190  {
6191  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6192  break;
6193  }
6194 
6195  SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6196  if( *infeasible )
6197  {
6198  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6199  break;
6200  }
6201  }
6202  }
6203 
6204  /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6205  * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6206  * (e.g., log(x*y), which becomes log(w), w=x*y
6207  * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6208  */
6209  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6210  if( result == SCIP_CUTOFF )
6211  *infeasible = TRUE;
6212 
6213  /* now call initsepa of nlhdlrs
6214  * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6215  * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6216  */
6218  for( c = 0; c < nconss && !*infeasible; ++c )
6219  {
6220  assert(conss != NULL);
6221  assert(conss[c] != NULL);
6222 
6223  consdata = SCIPconsGetData(conss[c]);
6224  assert(consdata != NULL);
6225  assert(consdata->expr != NULL);
6226 
6227  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6228  {
6229  SCIP_EXPR_OWNERDATA* ownerdata;
6230 
6231  ownerdata = SCIPexprGetOwnerData(expr);
6232  assert(ownerdata != NULL);
6233 
6234  if( ownerdata->nauxvaruses == 0 )
6235  continue;
6236 
6237  for( e = 0; e < ownerdata->nenfos; ++e )
6238  {
6239  SCIP_NLHDLR* nlhdlr;
6240  SCIP_Bool underestimate;
6241  SCIP_Bool overestimate;
6242  assert(ownerdata->enfos[e] != NULL);
6243 
6244  /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6245  * which participated in a previous initSepa() call
6246  */
6247  if( ownerdata->enfos[e]->issepainit )
6248  continue;
6249 
6250  /* only call initsepa if it will actually separate */
6251  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6252  continue;
6253 
6254  nlhdlr = ownerdata->enfos[e]->nlhdlr;
6255  assert(nlhdlr != NULL);
6256 
6257  /* only init sepa if there is an initsepa callback */
6258  if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6259  continue;
6260 
6261  /* check whether expression needs to be under- or overestimated */
6262  overestimate = ownerdata->nlocksneg > 0;
6263  underestimate = ownerdata->nlockspos > 0;
6264  assert(underestimate || overestimate);
6265 
6266  SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6267 
6268  /* call the separation initialization callback of the nonlinear handler */
6269  SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6270  ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6271  ownerdata->enfos[e]->issepainit = TRUE;
6272 
6273  if( *infeasible )
6274  {
6275  /* stop everything if we detected infeasibility */
6276  SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6277  break;
6278  }
6279  }
6280  }
6281  }
6282 
6283  SCIPfreeExpriter(&it);
6284 
6285  return SCIP_OKAY;
6286 }
6287 
6288 /** returns whether we are ok to branch on auxiliary variables
6289  *
6290  * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6291  */
6292 static
6294  SCIP* scip, /**< SCIP data structure */
6295  SCIP_CONSHDLR* conshdlr /**< constraint handler */
6296  )
6297 {
6298  SCIP_CONSHDLRDATA* conshdlrdata;
6299 
6300  assert(conshdlr != NULL);
6301 
6302  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6303  assert(conshdlrdata != NULL);
6304 
6305  return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6306 }
6307 
6308 /** gets weight of variable when splitting violation score onto several variables in an expression */
6309 static
6311  SCIP* scip, /**< SCIP data structure */
6312  SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6313  SCIP_VAR* var, /**< variable */
6314  SCIP_SOL* sol /**< current solution */
6315  )
6316 {
6317  SCIP_CONSHDLRDATA* conshdlrdata;
6318 
6319  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6320  assert(conshdlrdata != NULL);
6321 
6322  switch( conshdlrdata->branchviolsplit )
6323  {
6324  case 'u' : /* uniform: everyone gets the same score */
6325  return 1.0;
6326 
6327  case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6328  {
6329  SCIP_Real weight;
6330  weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6331  return MAX(0.05, weight);
6332  }
6333 
6334  case 'd' : /* domain width */
6335  return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6336 
6337  case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6338  {
6339  SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6340  assert(width > 0.0);
6341  if( width > 10.0 )
6342  return 10.0*log10(width);
6343  if( width < 0.1 )
6344  return 0.1/(-log10(width));
6345  return width;
6346  }
6347 
6348  default :
6349  SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6350  SCIPABORT();
6351  return SCIP_INVALID;
6352  }
6353 }
6354 
6355 /** adds violation-branching score to a set of expressions, thereby distributing the score
6356  *
6357  * Each expression must either be a variable expression or have an aux-variable.
6358  *
6359  * If unbounded variables are present, each unbounded var gets an even score.
6360  * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6361  */
6362 static
6363 void addExprsViolScore(
6364  SCIP* scip, /**< SCIP data structure */
6365  SCIP_EXPR** exprs, /**< expressions where to add branching score */
6366  int nexprs, /**< number of expressions */
6367  SCIP_Real violscore, /**< violation-branching score to add to expression */
6368  SCIP_SOL* sol, /**< current solution */
6369  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6370  )
6371 {
6372  SCIP_CONSHDLR* conshdlr;
6373  SCIP_VAR* var;
6374  SCIP_Real weight;
6375  SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6376  int nunbounded = 0; /* number of candidates with unbounded domain */
6377  int i;
6378 
6379  assert(exprs != NULL);
6380  assert(nexprs > 0);
6381  assert(success != NULL);
6382 
6383  if( nexprs == 1 )
6384  {
6385  SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6386  SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6388  *success = TRUE;
6389  return;
6390  }
6391 
6392  conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6393 
6394  for( i = 0; i < nexprs; ++i )
6395  {
6396  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6397  assert(var != NULL);
6398 
6399  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6400  ++nunbounded;
6401  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6402  weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6403  }
6404 
6405  *success = FALSE;
6406  for( i = 0; i < nexprs; ++i )
6407  {
6408  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6409  assert(var != NULL);
6410 
6411  if( nunbounded > 0 )
6412  {
6413  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6414  {
6415  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6416  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6417  100.0/nunbounded, violscore,
6419  *success = TRUE;
6420  }
6421  }
6422  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6423  {
6424  assert(weightsum > 0.0);
6425 
6426  weight = getViolSplitWeight(scip, conshdlr, var, sol);
6427  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6428  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6429  100*weight / weightsum, violscore,
6431  *success = TRUE;
6432  }
6433  else
6434  {
6435  SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6437  }
6438  }
6439 }
6440 
6441 /** adds violation-branching score to children of expression for given auxiliary variables
6442  *
6443  * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6444  * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6445  *
6446  * @note This method may modify the given auxvars array by means of sorting.
6447  */
6448 static
6450  SCIP* scip, /**< SCIP data structure */
6451  SCIP_EXPR* expr, /**< expression where to start searching */
6452  SCIP_Real violscore, /**< violation score to add to expression */
6453  SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6454  int nauxvars, /**< number of auxiliary variables */
6455  SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6456  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6457  )
6458 {
6459  SCIP_EXPRITER* it;
6460  SCIP_VAR* auxvar;
6461  SCIP_EXPR** exprs;
6462  int nexprs;
6463  int pos;
6464 
6465  assert(scip != NULL);
6466  assert(expr != NULL);
6467  assert(auxvars != NULL);
6468  assert(success != NULL);
6469 
6470  /* sort variables to make lookup below faster */
6471  SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6472 
6473  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6475 
6476  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6477  nexprs = 0;
6478 
6479  for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6480  {
6481  auxvar = SCIPgetExprAuxVarNonlinear(expr);
6482  if( auxvar == NULL )
6483  continue;
6484 
6485  /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6486  if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6487  {
6488  assert(auxvars[pos] == auxvar);
6489 
6490  SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6491  exprs[nexprs++] = expr;
6492 
6493  if( nexprs == nauxvars )
6494  break;
6495  }
6496  }
6497 
6498  SCIPfreeExpriter(&it);
6499 
6500  if( nexprs > 0 )
6501  {
6502  SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6503  }
6504  else
6505  *success = FALSE;
6506 
6507  SCIPfreeBufferArray(scip, &exprs);
6508 
6509  return SCIP_OKAY;
6510 }
6511 
6512 /** registers all unfixed variables in violated constraints as branching candidates */
6513 static
6515  SCIP* scip, /**< SCIP data structure */
6516  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6517  SCIP_CONS** conss, /**< constraints */
6518  int nconss, /**< number of constraints */
6519  int* nnotify /**< counter for number of notifications performed */
6520  )
6521 {
6522  SCIP_CONSDATA* consdata;
6523  SCIP_VAR* var;
6524  int c;
6525  int i;
6526 
6527  assert(conshdlr != NULL);
6528  assert(conss != NULL || nconss == 0);
6529  assert(nnotify != NULL);
6530 
6531  *nnotify = 0;
6532 
6533  for( c = 0; c < nconss; ++c )
6534  {
6535  assert(conss != NULL && conss[c] != NULL);
6536 
6537  consdata = SCIPconsGetData(conss[c]);
6538  assert(consdata != NULL);
6539 
6540  /* consider only violated constraints */
6541  if( !isConsViolated(scip, conss[c]) )
6542  continue;
6543 
6544  /* register all variables that have not been fixed yet */
6545  assert(consdata->varexprs != NULL);
6546  for( i = 0; i < consdata->nvarexprs; ++i )
6547  {
6548  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6549  assert(var != NULL);
6550 
6551  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6552  {
6554  ++(*nnotify);
6555  }
6556  }
6557  }
6558 
6559  return SCIP_OKAY;
6560 }
6561 
6562 /** registers all variables in violated constraints with branching scores as external branching candidates */
6563 static
6565  SCIP* scip, /**< SCIP data structure */
6566  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6567  SCIP_CONS** conss, /**< constraints */
6568  int nconss, /**< number of constraints */
6569  SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6570  )
6571 {
6572  SCIP_CONSDATA* consdata;
6573  SCIP_EXPRITER* it = NULL;
6574  int c;
6575 
6576  assert(conshdlr != NULL);
6577  assert(success != NULL);
6578 
6579  *success = FALSE;
6580 
6581  if( branchAuxNonlinear(scip, conshdlr) )
6582  {
6583  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6585  }
6586 
6587  /* register external branching candidates */
6588  for( c = 0; c < nconss; ++c )
6589  {
6590  assert(conss != NULL && conss[c] != NULL);
6591 
6592  consdata = SCIPconsGetData(conss[c]);
6593  assert(consdata != NULL);
6594  assert(consdata->varexprs != NULL);
6595 
6596  /* consider only violated constraints */
6597  if( !isConsViolated(scip, conss[c]) )
6598  continue;
6599 
6600  if( !branchAuxNonlinear(scip, conshdlr) )
6601  {
6602  int i;
6603 
6604  /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6605  * only, so we can loop over variable expressions
6606  */
6607  for( i = 0; i < consdata->nvarexprs; ++i )
6608  {
6609  SCIP_Real violscore;
6610  SCIP_Real lb;
6611  SCIP_Real ub;
6612  SCIP_VAR* var;
6613 
6614  violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6615 
6616  /* skip variable expressions that do not have a violation score */
6617  if( violscore == 0.0 )
6618  continue;
6619 
6620  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6621  assert(var != NULL);
6622 
6623  lb = SCIPvarGetLbLocal(var);
6624  ub = SCIPvarGetUbLocal(var);
6625 
6626  /* consider variable for branching if it has not been fixed yet */
6627  if( !SCIPisEQ(scip, lb, ub) )
6628  {
6629  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6630  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6631  *success = TRUE;
6632  }
6633  else
6634  {
6635  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6636  }
6637 
6638  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6639  * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6640  */
6641  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6642  }
6643  }
6644  else
6645  {
6646  SCIP_EXPR* expr;
6647  SCIP_VAR* var;
6648  SCIP_Real lb;
6649  SCIP_Real ub;
6650  SCIP_Real violscore;
6651 
6652  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6653  {
6654  violscore = SCIPgetExprViolScoreNonlinear(expr);
6655  if( violscore == 0.0 )
6656  continue;
6657 
6658  /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6659  * variable, so this expression should either be an original variable or have an auxiliary variable
6660  */
6661  var = SCIPgetExprAuxVarNonlinear(expr);
6662  assert(var != NULL);
6663 
6664  lb = SCIPvarGetLbLocal(var);
6665  ub = SCIPvarGetUbLocal(var);
6666 
6667  /* consider variable for branching if it has not been fixed yet */
6668  if( !SCIPisEQ(scip, lb, ub) )
6669  {
6670  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6671 
6672  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6673  *success = TRUE;
6674  }
6675  else
6676  {
6677  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6678  }
6679  }
6680  }
6681  }
6682 
6683  if( it != NULL )
6684  SCIPfreeExpriter(&it);
6685 
6686  return SCIP_OKAY;
6687 }
6688 
6689 /** collect branching candidates from violated constraints
6690  *
6691  * Fills array with expressions that serve as branching candidates.
6692  * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6693  * branching candidate.
6694  *
6695  * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6696  * through variable-expressions only.
6697  */
6698 static
6700  SCIP* scip, /**< SCIP data structure */
6701  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6702  SCIP_CONS** conss, /**< constraints to process */
6703  int nconss, /**< number of constraints */
6704  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6705  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6706  SCIP_Longint soltag, /**< tag of solution */
6707  BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6708  int* ncands /**< number of candidates found */
6709  )
6710 {
6711  SCIP_CONSHDLRDATA* conshdlrdata;
6712  SCIP_CONSDATA* consdata;
6713  SCIP_EXPRITER* it = NULL;
6714  int c;
6715  int attempt;
6716  SCIP_VAR* var;
6717 
6718  assert(scip != NULL);
6719  assert(conshdlr != NULL);
6720  assert(cands != NULL);
6721  assert(ncands != NULL);
6722 
6723  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6724  assert(conshdlrdata != NULL);
6725 
6726  if( branchAuxNonlinear(scip, conshdlr) )
6727  {
6728  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6730  }
6731 
6732  *ncands = 0;
6733  for( attempt = 0; attempt < 2; ++attempt )
6734  {
6735  /* collect branching candidates from violated constraints
6736  * in the first attempt, consider only constraints with large violation
6737  * in the second attempt, consider all remaining violated constraints
6738  */
6739  for( c = 0; c < nconss; ++c )
6740  {
6741  SCIP_Real consviol;
6742 
6743  assert(conss != NULL && conss[c] != NULL);
6744 
6745  /* consider only violated constraints */
6746  if( !isConsViolated(scip, conss[c]) )
6747  continue;
6748 
6749  consdata = SCIPconsGetData(conss[c]);
6750  assert(consdata != NULL);
6751  assert(consdata->varexprs != NULL);
6752 
6753  SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6754 
6755  if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6756  continue;
6757  else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6758  continue;
6759 
6760  if( !branchAuxNonlinear(scip, conshdlr) )
6761  {
6762  int i;
6763 
6764  /* if not branching on auxvars, then violation-branching scores will be available for original variables
6765  * only, so we can loop over variable expressions
6766  * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6767  * variable, therefore we invalidate the score of a variable after processing it.
6768  */
6769  for( i = 0; i < consdata->nvarexprs; ++i )
6770  {
6771  SCIP_Real lb;
6772  SCIP_Real ub;
6773 
6774  /* skip variable expressions that do not have a valid violation score */
6775  if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6776  continue;
6777 
6778  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6779  assert(var != NULL);
6780 
6781  lb = SCIPvarGetLbLocal(var);
6782  ub = SCIPvarGetUbLocal(var);
6783 
6784  /* skip already fixed variable */
6785  if( SCIPisEQ(scip, lb, ub) )
6786  {
6787  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6788  continue;
6789  }
6790 
6791  assert(*ncands + 1 < SCIPgetNVars(scip));
6792  cands[*ncands].expr = consdata->varexprs[i];
6793  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6794  ++(*ncands);
6795 
6796  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6797  * several times as external branching candidate */
6798  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6799  }
6800  }
6801  else
6802  {
6803  SCIP_EXPR* expr;
6804  SCIP_Real lb;
6805  SCIP_Real ub;
6806 
6807  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6808  {
6809  if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6810  continue;
6811 
6812  /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6813  * variables, so this expression should either be an original variable or have an auxiliary variable
6814  */
6815  var = SCIPgetExprAuxVarNonlinear(expr);
6816  assert(var != NULL);
6817 
6818  lb = SCIPvarGetLbLocal(var);
6819  ub = SCIPvarGetUbLocal(var);
6820 
6821  /* skip already fixed variable */
6822  if( SCIPisEQ(scip, lb, ub) )
6823  {
6824  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6825  continue;
6826  }
6827 
6828  assert(*ncands + 1 < SCIPgetNVars(scip));
6829  cands[*ncands].expr = expr;
6830  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6831  ++(*ncands);
6832  }
6833  }
6834  }
6835 
6836  /* if we have branching candidates, then we don't need another attempt */
6837  if( *ncands > 0 )
6838  break;
6839  }
6840 
6841  if( it != NULL )
6842  SCIPfreeExpriter(&it);
6843 
6844  return SCIP_OKAY;
6845 }
6846 
6847 /** computes a branching score for a variable that reflects how important branching on this variable would be for
6848  * improving the dual bound from the LP relaxation
6849  *
6850  * Assume the Lagrangian for the current LP is something of the form
6851  * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6852  * where x are the original variables, z the auxiliary variables,
6853  * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6854  *
6855  * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6856  * If we could have used not only an estimator, but the actual function f(x), then this would
6857  * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6858  * Using a lot of handwaving, we claim that
6859  * lambda_i * (f(x) - a_i'x + b_i)
6860  * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6861  * If an estimator depended on local bounds, then it could be improved by branching.
6862  * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6863  *
6864  * 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.
6865  * To scale, we divide by the LP objective value (if >1).
6866  *
6867  * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6868  * these are affected by the bounds on original variables indirectly (through forward-propagation)
6869  *
6870  * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6871  * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6872  * would also be branching candidates
6873  */
6874 static
6876  SCIP* scip, /**< SCIP data structure */
6877  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6878  SCIP_VAR* var /**< variable */
6879  )
6880 {
6881  SCIP_COL* col;
6882  SCIP_ROW** rows;
6883  int nrows;
6884  int r;
6885  SCIP_Real dualscore;
6886 
6887  assert(scip != NULL);
6888  assert(conshdlr != NULL);
6889  assert(var != NULL);
6890 
6891  /* if LP not solved, then the dual branching score is not available */
6893  return 0.0;
6894 
6895  /* if var is not in the LP, then the dual branching score is not available */
6897  return 0.0;
6898 
6899  col = SCIPvarGetCol(var);
6900  assert(col != NULL);
6901 
6902  if( !SCIPcolIsInLP(col) )
6903  return 0.0;
6904 
6905  nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6906  rows = SCIPcolGetRows(col);
6907 
6908  /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6909 
6910  /* aggregate duals from all rows from consexpr with non-zero dual
6911  * TODO: this is a quick-and-dirty implementation, and not used by default
6912  * in the long run, this should be either removed or replaced by a proper implementation
6913  */
6914  dualscore = 0.0;
6915  for( r = 0; r < nrows; ++r )
6916  {
6917  SCIP_Real estimategap;
6918  const char* estimategapstr;
6919 
6920  /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6921  * these would typically be local, unless they are created at the root node
6922  * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6923  if( !SCIProwIsLocal(rows[r]) )
6924  continue;
6925  */
6926  if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6927  continue;
6928  if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6929  continue;
6930 
6931  estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6932  if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6933  continue;
6934  estimategap = atof(estimategapstr + 13);
6935  assert(estimategap >= 0.0);
6936  if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6937  estimategap = SCIPgetHugeValue(scip);
6938 
6939  /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6940  SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6941 
6942  dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6943  }
6944 
6945  /* divide by optimal value of LP for scaling */
6946  dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6947 
6948  return dualscore;
6949 }
6950 
6951 /** computes branching scores (including weighted score) for a set of candidates
6952  *
6953  * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6954  * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6955  *
6956  * For each score, compute the maximum over all candidates.
6957  *
6958  * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6959  * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6960  * score of all candidates.
6961  * Further divide by the sum of all weights where a score was available (even if the score was 0).
6962  *
6963  * For example:
6964  * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6965  * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6966  * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6967  * - 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.
6968  * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6969  */
6970 static
6972  SCIP* scip, /**< SCIP data structure */
6973  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6974  BRANCHCAND* cands, /**< branching candidates */
6975  int ncands, /**< number of candidates */
6976  SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6977  )
6978 {
6979  SCIP_CONSHDLRDATA* conshdlrdata;
6980  BRANCHCAND maxscore;
6981  int c;
6982 
6983  assert(scip != NULL);
6984  assert(conshdlr != NULL);
6985  assert(cands != NULL);
6986  assert(ncands > 0);
6987 
6988  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6989  assert(conshdlrdata != NULL);
6990 
6991  /* initialize counts to 0 */
6992  memset(&maxscore, 0, sizeof(BRANCHCAND));
6993 
6994  for( c = 0; c < ncands; ++c )
6995  {
6996  if( conshdlrdata->branchviolweight > 0.0 )
6997  {
6998  /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6999  maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
7000  }
7001 
7002  if( conshdlrdata->branchdomainweight > 0.0 )
7003  {
7004  SCIP_Real domainwidth;
7005  SCIP_VAR* var;
7006 
7007  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7008  assert(var != NULL);
7009 
7010  /* get domain width, taking infinity at 1e20 on purpose */
7011  domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
7012 
7013  /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
7014  * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
7015  * the idea is to penalize very large and very small domains
7016  */
7017  if( domainwidth >= 1.0 )
7018  cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7019  else
7020  cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
7021 
7022  maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7023  }
7024  else
7025  cands[c].domain = 0.0;
7026 
7027  if( conshdlrdata->branchdualweight > 0.0 )
7028  {
7029  SCIP_VAR* var;
7030 
7031  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7032  assert(var != NULL);
7033 
7034  cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7035  maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7036  }
7037 
7038  if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7039  {
7040  SCIP_VAR* var;
7041 
7042  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7043  assert(var != NULL);
7044 
7045  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
7046  cands[c].pscost = SCIP_INVALID;
7047  else
7048  {
7049  SCIP_Real brpoint;
7050  SCIP_Real pscostdown;
7051  SCIP_Real pscostup;
7052  char strategy;
7053 
7054  /* decide how to compute pseudo-cost scores
7055  * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7056  * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7057  */
7059  strategy = conshdlrdata->branchpscostupdatestrategy;
7060  else
7061  strategy = 'l';
7062 
7063  brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7064 
7065  /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7066  * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7067  * For here, I use a simple #counts >= branchpscostreliable.
7068  * TODO use SCIPgetVarPseudocostCount() instead?
7069  */
7070  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7071  {
7072  switch( strategy )
7073  {
7074  case 's' :
7075  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7076  break;
7077  case 'd' :
7078  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7079  break;
7080  case 'l' :
7081  if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7082  pscostdown = SCIP_INVALID;
7083  else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7084  pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7085  else
7086  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, NULL, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7087  break;
7088  default :
7089  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7090  pscostdown = SCIP_INVALID;
7091  }
7092  }
7093  else
7094  pscostdown = SCIP_INVALID;
7095 
7096  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7097  {
7098  switch( strategy )
7099  {
7100  case 's' :
7101  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7102  break;
7103  case 'd' :
7104  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7105  break;
7106  case 'l' :
7107  if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7108  pscostup = SCIP_INVALID;
7109  else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7110  pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7111  else
7112  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, NULL, var) );
7113  break;
7114  default :
7115  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7116  pscostup = SCIP_INVALID;
7117  }
7118  }
7119  else
7120  pscostup = SCIP_INVALID;
7121 
7122  /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7123  * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7124  */
7125  if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7126  cands[c].pscost = SCIP_INVALID;
7127  else if( pscostdown == SCIP_INVALID )
7128  cands[c].pscost = pscostup;
7129  else if( pscostup == SCIP_INVALID )
7130  cands[c].pscost = pscostdown;
7131  else
7132  cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7133  }
7134 
7135  if( cands[c].pscost != SCIP_INVALID )
7136  maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7137  }
7138 
7139  if( conshdlrdata->branchvartypeweight > 0.0 )
7140  {
7141  SCIP_VAR* var;
7142 
7143  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7144  assert(var != NULL);
7145 
7146  switch( SCIPvarGetType(var) )
7147  {
7148  case SCIP_VARTYPE_BINARY :
7149  cands[c].vartype = 1.0;
7150  break;
7151  case SCIP_VARTYPE_INTEGER :
7152  cands[c].vartype = 0.1;
7153  break;
7154  case SCIP_VARTYPE_IMPLINT :
7155  cands[c].vartype = 0.01;
7156  break;
7158  default:
7159  cands[c].vartype = 0.0;
7160  }
7161  maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7162  }
7163  }
7164 
7165  /* now compute a weighted score for each candidate from the single scores
7166  * the single scores are scaled to be in [0,1] for this
7167  */
7168  for( c = 0; c < ncands; ++c )
7169  {
7170  SCIP_Real weightsum;
7171 
7172  ENFOLOG(
7173  SCIP_VAR* var;
7174  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7175  SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7176  )
7177 
7178  cands[c].weighted = 0.0;
7179  weightsum = 0.0;
7180 
7181  if( maxscore.auxviol > 0.0 )
7182  {
7183  cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7184  weightsum += conshdlrdata->branchviolweight;
7185 
7186  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7187  }
7188 
7189  if( maxscore.domain > 0.0 )
7190  {
7191  cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7192  weightsum += conshdlrdata->branchdomainweight;
7193 
7194  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7195  }
7196 
7197  if( maxscore.dual > 0.0 )
7198  {
7199  cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7200  weightsum += conshdlrdata->branchdualweight;
7201 
7202  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7203  }
7204 
7205  if( maxscore.pscost > 0.0 )
7206  {
7207  /* use pseudo-costs only if available */
7208  if( cands[c].pscost != SCIP_INVALID )
7209  {
7210  cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7211  weightsum += conshdlrdata->branchpscostweight;
7212 
7213  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7214  }
7215  else
7216  {
7217  /* do not add pscostscore, if not available, also do not add into weightsum */
7218  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7219  }
7220  }
7221 
7222  if( maxscore.vartype > 0.0 )
7223  {
7224  cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7225  weightsum += conshdlrdata->branchvartypeweight;
7226 
7227  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7228  }
7229  assert(weightsum > 0.0); /* we should have got at least one valid score */
7230  cands[c].weighted /= weightsum;
7231 
7232  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7233  }
7234 }
7235 
7236 /** compare two branching candidates by their weighted score
7237  *
7238  * if weighted score is equal, use variable index of (aux)var
7239  */
7240 static
7241 SCIP_DECL_SORTINDCOMP(branchcandCompare)
7243  BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7244 
7245  if( cands[ind1].weighted != cands[ind2].weighted )
7246  return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7247  else
7248  return SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind1].expr)) - SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind2].expr));
7249 }
7250 
7251 /** do branching or register branching candidates */
7252 static
7254  SCIP* scip, /**< SCIP data structure */
7255  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7256  SCIP_CONS** conss, /**< constraints to process */
7257  int nconss, /**< number of constraints */
7258  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7259  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7260  SCIP_Longint soltag, /**< tag of solution */
7261  SCIP_RESULT* result /**< pointer to store the result of branching */
7262  )
7263 {
7264  SCIP_CONSHDLRDATA* conshdlrdata;
7265  BRANCHCAND* cands;
7266  int ncands;
7267  SCIP_VAR* var;
7268  SCIP_NODE* downchild;
7269  SCIP_NODE* eqchild;
7270  SCIP_NODE* upchild;
7271 
7272  assert(conshdlr != NULL);
7273  assert(result != NULL);
7274 
7275  *result = SCIP_DIDNOTFIND;
7276 
7277  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7278  assert(conshdlrdata != NULL);
7279 
7280  if( conshdlrdata->branchexternal )
7281  {
7282  /* just register branching candidates as external */
7283  SCIP_Bool success;
7284 
7285  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7286  if( success )
7287  *result = SCIP_INFEASIBLE;
7288 
7289  return SCIP_OKAY;
7290  }
7291 
7292  /* collect branching candidates and their auxviol-score */
7293  SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip)) );
7294  SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7295 
7296  /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7297  * we will return here and let the fallbacks in consEnfo() decide how to proceed
7298  */
7299  if( ncands == 0 )
7300  goto TERMINATE;
7301 
7302  if( ncands > 1 )
7303  {
7304  /* if there are more than one candidate, then compute scores and select */
7305  int* perm;
7306  int c;
7307  int left;
7308  int right;
7309  SCIP_Real threshold;
7310 
7311  /* compute additional scores on branching candidates and weighted score */
7312  scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7313 
7314  /* sort candidates by weighted score */
7315  SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7316  SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7317 
7318  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7319  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7320  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7321 
7322  /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7323  left = 0;
7324  right = ncands - 1;
7325  threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7326  while( left < right )
7327  {
7328  int mid = (left + right) / 2;
7329  if( cands[perm[mid]].weighted >= threshold )
7330  left = mid + 1;
7331  else
7332  right = mid;
7333  }
7334  assert(left <= ncands);
7335 
7336  if( left < ncands )
7337  {
7338  if( cands[perm[left]].weighted >= threshold )
7339  {
7340  assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7341  ncands = left + 1;
7342  }
7343  else
7344  {
7345  assert(cands[perm[left]].weighted < threshold);
7346  ncands = left;
7347  }
7348  }
7349  assert(ncands > 0);
7350 
7351  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7352  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7353  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7354 
7355  if( ncands > 1 )
7356  {
7357  /* choose at random from candidates 0..ncands-1 */
7358  if( conshdlrdata->branchrandnumgen == NULL )
7359  {
7360  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7361  }
7362  c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7363  var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7364  }
7365  else
7366  var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7367 
7368  SCIPfreeBufferArray(scip, &perm);
7369  }
7370  else
7371  {
7372  var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7373  }
7374  assert(var != NULL);
7375 
7376  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7377  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); )
7378 
7379  SCIP_CALL( SCIPbranchVarVal(scip, var, SCIPgetBranchingPoint(scip, var, SCIP_INVALID), &downchild, &eqchild,
7380  &upchild) );
7381  if( downchild != NULL || eqchild != NULL || upchild != NULL )
7382  *result = SCIP_BRANCHED;
7383  else
7384  /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7385  *result = SCIP_REDUCEDDOM;
7386 
7387  TERMINATE:
7388  SCIPfreeBufferArray(scip, &cands);
7389 
7390  return SCIP_OKAY;
7391 }
7392 
7393 /** call enforcement or estimate callback of nonlinear handler
7394  *
7395  * Calls the enforcement callback, if available.
7396  * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7397  *
7398  * If cut is weak, but estimator is not tight, tries to add branching candidates.
7399  */
7400 static
7402  SCIP* scip, /**< SCIP main data structure */
7403  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7404  SCIP_CONS* cons, /**< nonlinear constraint */
7405  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7406  SCIP_EXPR* expr, /**< expression */
7407  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7408  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7409  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7410  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7411  SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7412  SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7413  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7414  SCIP_RESULT* result /**< pointer to store the result */
7415  )
7416 {
7417  assert(result != NULL);
7418 
7419  /* call enforcement callback of the nlhdlr */
7420  SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7421  allowweakcuts, separated, inenforcement, result) );
7422 
7423  /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7424  if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7425  {
7426  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr %s succeeded with result %d\n",
7427  SCIPnlhdlrGetName(nlhdlr), *result); )
7428  return SCIP_OKAY;
7429  }
7430  else
7431  {
7432  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7433  }
7434 
7435  *result = SCIP_DIDNOTFIND;
7436 
7437  /* now call the estimator callback of the nlhdlr */
7438  if( SCIPnlhdlrHasEstimate(nlhdlr) )
7439  {
7440  SCIP_VAR* auxvar;
7441  SCIP_Bool sepasuccess = FALSE;
7442  SCIP_Bool branchscoresuccess = FALSE;
7443  SCIP_PTRARRAY* rowpreps;
7444  int minidx;
7445  int maxidx;
7446  int r;
7447  SCIP_ROWPREP* rowprep;
7448 
7449  SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7450 
7451  auxvar = SCIPgetExprAuxVarNonlinear(expr);
7452  assert(auxvar != NULL);
7453 
7454  SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7455  SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7456 
7457  minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7458  maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7459 
7460  assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7461 
7462  if( !sepasuccess )
7463  {
7464  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7465  SCIPnlhdlrGetName(nlhdlr)); )
7466  }
7467 
7468  for( r = minidx; r <= maxidx; ++r )
7469  {
7470  rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7471 
7472  assert(rowprep != NULL);
7473  assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7474 
7475  /* complete estimator to cut */
7476  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7477 
7478  /* add the cut and/or branching scores */
7479  SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7480  auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7481 
7482  SCIPfreeRowprep(scip, &rowprep);
7483  }
7484 
7485  SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7486  }
7487 
7488  return SCIP_OKAY;
7489 }
7490 
7491 /** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7492  *
7493  * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7494  */
7495 static
7497  SCIP* scip, /**< SCIP data structure */
7498  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7499  SCIP_CONS* cons, /**< nonlinear constraint */
7500  SCIP_EXPR* expr, /**< expression */
7501  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7502  SCIP_Longint soltag, /**< tag of solution */
7503  SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7504  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7505  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7506  )
7507 {
7508  SCIP_CONSHDLRDATA* conshdlrdata;
7509  SCIP_EXPR_OWNERDATA* ownerdata;
7510  SCIP_Real origviol;
7511  SCIP_Bool underestimate;
7512  SCIP_Bool overestimate;
7513  SCIP_Real auxviol;
7514  SCIP_Bool auxunderestimate;
7515  SCIP_Bool auxoverestimate;
7516  SCIP_RESULT hdlrresult;
7517  int e;
7518 
7519  assert(scip != NULL);
7520  assert(expr != NULL);
7521  assert(result != NULL);
7522 
7523  ownerdata = SCIPexprGetOwnerData(expr);
7524  assert(ownerdata != NULL);
7525  assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7526 
7527  *result = SCIP_DIDNOTFIND;
7528 
7529  /* make sure that this expression has been evaluated */
7530  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7531 
7532  /* decide whether under- or overestimate is required and get amount of violation */
7533  origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7534 
7535  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7536  assert(conshdlrdata != NULL);
7537 
7538  /* no sufficient violation w.r.t. the original variables -> skip expression */
7539  if( !overestimate && !underestimate )
7540  {
7541  return SCIP_OKAY;
7542  }
7543 
7544  /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7545  for( e = 0; e < ownerdata->nenfos; ++e )
7546  {
7547  SCIP_NLHDLR* nlhdlr;
7548 
7549  /* skip nlhdlr that do not want to participate in any separation */
7550  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7551  continue;
7552 
7553  nlhdlr = ownerdata->enfos[e]->nlhdlr;
7554  assert(nlhdlr != NULL);
7555 
7556  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7557  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7558  ENFOLOG(
7559  SCIPinfoMessage(scip, enfologfile, " expr ");
7560  SCIPprintExpr(scip, expr, enfologfile);
7561  SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7562  "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7563  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7564  )
7565 
7566  /* TODO if expr is root of constraint (consdata->expr == expr),
7567  * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7568  * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7569  * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7570  * so we should enforce in these auxiliaries first
7571  * if changing this here, we must also adapt analyzeViolation()
7572  */
7573 
7574  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7575  assert(auxviol >= 0.0);
7576 
7577  /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7578  if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7579  {
7580  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7581  "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7582  SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7583 
7584  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7585  continue;
7586  }
7587 
7588  /* 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 */
7589  if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7590  {
7591  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7592  "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7593  underestimate, overestimate); )
7594 
7595  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7596  continue;
7597  }
7598 
7599  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7600  "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7601  auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7602 
7603  /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7604  * wants to be called for separation on this side, then call separation of nlhdlr
7605  */
7606  if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7607  {
7608  /* call the separation or estimation callback of the nonlinear handler for overestimation */
7609  hdlrresult = SCIP_DIDNOTFIND;
7610  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7611  ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7612 
7613  if( hdlrresult == SCIP_CUTOFF )
7614  {
7615  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7616  *result = SCIP_CUTOFF;
7617  ownerdata->lastenforced = conshdlrdata->enforound;
7618  break;
7619  }
7620 
7621  if( hdlrresult == SCIP_SEPARATED )
7622  {
7623  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7624  *result = SCIP_SEPARATED;
7625  ownerdata->lastenforced = conshdlrdata->enforound;
7626  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7627  break;
7628  }
7629 
7630  if( hdlrresult == SCIP_REDUCEDDOM )
7631  {
7632  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7633  *result = SCIP_REDUCEDDOM;
7634  ownerdata->lastenforced = conshdlrdata->enforound;
7635  /* TODO or should we always just stop here? */
7636  }
7637 
7638  if( hdlrresult == SCIP_BRANCHED )
7639  {
7640  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7641  assert(inenforcement);
7642 
7643  /* separation and domain reduction takes precedence over branching */
7644  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7645  if( *result == SCIP_DIDNOTFIND )
7646  *result = SCIP_BRANCHED;
7647  ownerdata->lastenforced = conshdlrdata->enforound;
7648  }
7649  }
7650 
7651  /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7652  * wants to be called for separation on this side, then call separation of nlhdlr
7653  */
7654  if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7655  {
7656  /* call the separation or estimation callback of the nonlinear handler for underestimation */
7657  hdlrresult = SCIP_DIDNOTFIND;
7658  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7659  ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7660 
7661  if( hdlrresult == SCIP_CUTOFF )
7662  {
7663  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7664  *result = SCIP_CUTOFF;
7665  ownerdata->lastenforced = conshdlrdata->enforound;
7666  break;
7667  }
7668 
7669  if( hdlrresult == SCIP_SEPARATED )
7670  {
7671  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7672  *result = SCIP_SEPARATED;
7673  ownerdata->lastenforced = conshdlrdata->enforound;
7674  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7675  break;
7676  }
7677 
7678  if( hdlrresult == SCIP_REDUCEDDOM )
7679  {
7680  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7681  *result = SCIP_REDUCEDDOM;
7682  ownerdata->lastenforced = conshdlrdata->enforound;
7683  /* TODO or should we always just stop here? */
7684  }
7685 
7686  if( hdlrresult == SCIP_BRANCHED )
7687  {
7688  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7689  assert(inenforcement);
7690 
7691  /* separation takes precedence over branching */
7692  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7693  if( *result == SCIP_DIDNOTFIND )
7694  *result = SCIP_BRANCHED;
7695  ownerdata->lastenforced = conshdlrdata->enforound;
7696  }
7697  }
7698  }
7699 
7700  return SCIP_OKAY;
7701 }
7702 
7703 /** helper function to enforce a single constraint */
7704 static
7706  SCIP* scip, /**< SCIP data structure */
7707  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7708  SCIP_CONS* cons, /**< constraint to process */
7709  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7710  SCIP_Longint soltag, /**< tag of solution */
7711  SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7712  SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7713  SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7714  SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7715  SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7716  )
7717 {
7718  SCIP_CONSDATA* consdata;
7719  SCIP_CONSHDLRDATA* conshdlrdata;
7720  SCIP_EXPR* expr;
7721 
7722  assert(conshdlr != NULL);
7723  assert(cons != NULL);
7724  assert(it != NULL);
7725  assert(result != NULL);
7726  assert(success != NULL);
7727 
7728  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7729  assert(conshdlrdata != NULL);
7730 
7731  consdata = SCIPconsGetData(cons);
7732  assert(consdata != NULL);
7733  assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7734 
7735  *success = FALSE;
7736 
7737  if( inenforcement && !consdata->ispropagated )
7738  {
7739  /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7740  * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7741  * (TODO: nlhdlr tells us now whether they do and so we could skip).
7742  * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7743  * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7744  * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7745  * confuse the stalling check for how long to do separation).
7746  */
7747  SCIP_Bool infeasible;
7748  int ntightenings;
7749 
7750  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7751  if( infeasible )
7752  {
7753  *result = SCIP_CUTOFF;
7754  return SCIP_OKAY;
7755  }
7756  /* if we tightened an auxvar bound, we better communicate that */
7757  if( ntightenings > 0 )
7758  *result = SCIP_REDUCEDDOM;
7759  }
7760 
7761  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7762  {
7763  SCIP_EXPR_OWNERDATA* ownerdata;
7764  SCIP_RESULT resultexpr;
7765 
7766  ownerdata = SCIPexprGetOwnerData(expr);
7767  assert(ownerdata != NULL);
7768 
7769  /* we can only enforce if there is an auxvar to compare with */
7770  if( ownerdata->auxvar == NULL )
7771  continue;
7772 
7773  assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7774  if( ownerdata->lastenforced == conshdlrdata->enforound )
7775  {
7776  ENFOLOG(
7777  SCIPinfoMessage(scip, enfologfile, " skip expr ");
7778  SCIPprintExpr(scip, expr, enfologfile);
7779  SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7780  )
7781  *success = TRUE;
7782  continue;
7783  }
7784 
7785  SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7786 
7787  /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7788  assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7789  if( ownerdata->lastenforced == conshdlrdata->enforound )
7790  *success = TRUE;
7791 
7792  if( resultexpr == SCIP_CUTOFF )
7793  {
7794  *result = SCIP_CUTOFF;
7795  break;
7796  }
7797 
7798  if( resultexpr == SCIP_SEPARATED )
7799  *result = SCIP_SEPARATED;
7800 
7801  if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7802  *result = SCIP_REDUCEDDOM;
7803 
7804  if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7805  *result = SCIP_BRANCHED;
7806  }
7807 
7808  return SCIP_OKAY;
7809 }
7810 
7811 /** try to separate violated constraints and, if in enforcement, register branching scores
7812  *
7813  * Sets result to
7814  * - SCIP_DIDNOTFIND, if nothing of the below has been done
7815  * - SCIP_CUTOFF, if node can be cutoff,
7816  * - SCIP_SEPARATED, if a cut has been added,
7817  * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7818  * - SCIP_BRANCHED, if branching has been done,
7819  * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7820  * - SCIP_INFEASIBLE, if external branching candidates were registered
7821  */
7822 static
7824  SCIP* scip, /**< SCIP data structure */
7825  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7826  SCIP_CONS** conss, /**< constraints to process */
7827  int nconss, /**< number of constraints */
7828  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7829  SCIP_Longint soltag, /**< tag of solution */
7830  SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7831  SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7832  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7833  )
7834 {
7835  SCIP_CONSHDLRDATA* conshdlrdata;
7836  SCIP_EXPRITER* it;
7837  SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7838  int c;
7839 
7840  assert(conshdlr != NULL);
7841  assert(conss != NULL || nconss == 0);
7842  assert(result != NULL);
7843 
7844  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7845  assert(conshdlrdata != NULL);
7846 
7847  /* increase tag to tell whether branching scores in expression belong to this sweep
7848  * and which expressions have already been enforced in this sweep
7849  * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7850  */
7851  ++(conshdlrdata->enforound);
7852 
7853  *result = SCIP_DIDNOTFIND;
7854 
7855  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7857 
7858  for( c = 0; c < nconss; ++c )
7859  {
7860  assert(conss != NULL && conss[c] != NULL);
7861 
7862  /* skip constraints that are not enabled or deleted */
7863  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7864  continue;
7865  assert(SCIPconsIsActive(conss[c]));
7866 
7867  /* skip constraints that have separation disabled if we are only in separation */
7868  if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7869  continue;
7870 
7871  /* skip non-violated constraints */
7872  if( !isConsViolated(scip, conss[c]) )
7873  continue;
7874 
7875  ENFOLOG(
7876  {
7877  SCIP_CONSDATA* consdata;
7878  int i;
7879  consdata = SCIPconsGetData(conss[c]);
7880  assert(consdata != NULL);
7881  SCIPinfoMessage(scip, enfologfile, " constraint ");
7882  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7883  SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7884  for( i = 0; i < consdata->nvarexprs; ++i )
7885  {
7886  SCIP_VAR* var;
7887  var = SCIPgetVarExprVar(consdata->varexprs[i]);
7888  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7889  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7890  }
7891  })
7892 
7893  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, result, &consenforced) );
7894 
7895  if( *result == SCIP_CUTOFF )
7896  break;
7897 
7898  if( !consenforced && inenforcement )
7899  {
7900  SCIP_Real viol;
7901 
7902  SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7903  if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7904  {
7905  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7906  "cuts allowed\n", SCIPconsGetName(conss[c])); )
7907 
7908  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, result, &consenforced) );
7909 
7910  if( consenforced )
7911  ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7912 
7913  if( *result == SCIP_CUTOFF )
7914  break;
7915  }
7916  }
7917  }
7918 
7919  SCIPfreeExpriter(&it);
7920 
7921  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7922 
7923  /* if having branching scores, then propagate them from expressions with children to variable expressions */
7924  if( *result == SCIP_BRANCHED )
7925  {
7926  /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7927  * branching
7928  */
7929  SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7930 
7931  /* branching should either have branched: result == SCIP_BRANCHED,
7932  * or fixed a variable: result == SCIP_REDUCEDDOM,
7933  * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7934  * or have not done anything: result == SCIP_DIDNOTFIND
7935  */
7936  assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7937  }
7938 
7939  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7940 
7941  return SCIP_OKAY;
7942 }
7943 
7944 /** collect (and print (if debugging enfo)) information on violation in expressions
7945  *
7946  * assumes that constraint violations have been computed
7947  */
7948 static
7950  SCIP* scip, /**< SCIP data structure */
7951  SCIP_CONS** conss, /**< constraints */
7952  int nconss, /**< number of constraints */
7953  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7954  SCIP_Longint soltag, /**< tag of solution */
7955  SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
7956  SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
7957  SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
7958  SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7959  SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
7960  )
7961 {
7962  SCIP_CONSDATA* consdata;
7963  SCIP_EXPRITER* it;
7964  SCIP_EXPR* expr;
7965  SCIP_Real v;
7966  int c;
7967 
7968  assert(conss != NULL || nconss == 0);
7969  assert(maxabsconsviol != NULL);
7970  assert(maxrelconsviol != NULL);
7971  assert(maxauxviol != NULL);
7972  assert(maxvarboundviol != NULL);
7973 
7974  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7976 
7977  *maxabsconsviol = 0.0;
7978  *maxrelconsviol = 0.0;
7979  *minauxviol = SCIPinfinity(scip);
7980  *maxauxviol = 0.0;
7981  *maxvarboundviol = 0.0;
7982 
7983  for( c = 0; c < nconss; ++c )
7984  {
7985  assert(conss != NULL && conss[c] != NULL);
7986 
7987  consdata = SCIPconsGetData(conss[c]);
7988  assert(consdata != NULL);
7989 
7990  /* skip constraints that are not enabled, deleted, or have separation disabled */
7991  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7992  continue;
7993  assert(SCIPconsIsActive(conss[c]));
7994 
7995  v = getConsAbsViolation(conss[c]);
7996  *maxabsconsviol = MAX(*maxabsconsviol, v);
7997 
7998  /* skip non-violated constraints */
7999  if( !isConsViolated(scip, conss[c]) )
8000  continue;
8001 
8002  SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
8003  *maxrelconsviol = MAX(*maxrelconsviol, v);
8004 
8005  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8006  {
8007  SCIP_EXPR_OWNERDATA* ownerdata;
8008  SCIP_Real auxvarvalue;
8009  SCIP_Real auxvarlb;
8010  SCIP_Real auxvarub;
8011  SCIP_Bool violunder;
8012  SCIP_Bool violover;
8013  SCIP_Real origviol;
8014  SCIP_Real auxviol;
8015  int e;
8016 
8017  ownerdata = SCIPexprGetOwnerData(expr);
8018  assert(ownerdata != NULL);
8019 
8020  if( ownerdata->auxvar == NULL )
8021  {
8022  /* check violation of variable bounds of original variable */
8023  if( SCIPisExprVar(scip, expr) )
8024  {
8025  SCIP_VAR* var;
8026  var = SCIPgetVarExprVar(expr);
8027  auxvarvalue = SCIPgetSolVal(scip, sol, var);
8028  auxvarlb = SCIPvarGetLbLocal(var);
8029  auxvarub = SCIPvarGetUbLocal(var);
8030 
8031  origviol = 0.0;
8032  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8033  origviol = auxvarlb - auxvarvalue;
8034  else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8035  origviol = auxvarvalue - auxvarub;
8036  if( origviol <= 0.0 )
8037  continue;
8038 
8039  *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8040 
8041  ENFOLOG(
8042  SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8043  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8044  SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8045  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8046  SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8047  SCIPinfoMessage(scip, enfologfile, "\n");
8048  )
8049  }
8050 
8051  continue;
8052  }
8053 
8054  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8055  auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8056  auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8057 
8058  /* check violation of variable bounds of auxiliary variable */
8059  if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8060  *maxvarboundviol = auxvarlb - auxvarvalue;
8061  else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8062  *maxvarboundviol = auxvarvalue - auxvarub;
8063 
8064  origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8065 
8066  ENFOLOG(
8067  if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8068  {
8069  SCIPinfoMessage(scip, enfologfile, "expr ");
8070  SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8071  SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8072 
8073  SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8074  if( origviol > 0.0 )
8075  SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8076  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8077  SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8078  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8079  SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8080  SCIPinfoMessage(scip, enfologfile, "\n");
8081  }
8082  )
8083 
8084  /* no violation w.r.t. the original variables -> skip expression */
8085  if( origviol == 0.0 )
8086  continue;
8087 
8088  /* compute aux-violation for each nonlinear handlers */
8089  for( e = 0; e < ownerdata->nenfos; ++e )
8090  {
8091  SCIP_NLHDLR* nlhdlr;
8092 
8093  /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8094  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8095  continue;
8096 
8097  nlhdlr = ownerdata->enfos[e]->nlhdlr;
8098  assert(nlhdlr != NULL);
8099 
8100  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8101  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8102 
8103  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8104 
8105  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8106 
8107  if( auxviol > 0.0 )
8108  {
8109  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8110  *maxauxviol = MAX(*maxauxviol, auxviol);
8111  *minauxviol = MIN(*minauxviol, auxviol);
8112  }
8113  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8114  }
8115  }
8116  }
8117 
8118  SCIPfreeExpriter(&it);
8119 
8120  return SCIP_OKAY;
8121 } /*lint !e715*/
8122 
8123 /** enforcement of constraints called by enfolp and enforelax */
8124 static
8126  SCIP* scip, /**< SCIP data structure */
8127  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8128  SCIP_CONS** conss, /**< constraints to process */
8129  int nconss, /**< number of constraints */
8130  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8131  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8132  )
8133 {
8134  SCIP_CONSHDLRDATA* conshdlrdata;
8135  SCIP_Real maxabsconsviol;
8136  SCIP_Real maxrelconsviol;
8137  SCIP_Real minauxviol;
8138  SCIP_Real maxauxviol;
8139  SCIP_Real maxvarboundviol;
8140  SCIP_Longint soltag;
8141  int nnotify;
8142  int c;
8143 
8144  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8145  assert(conshdlr != NULL);
8146 
8147  soltag = SCIPgetExprNewSoltag(scip);
8148 
8149  *result = SCIP_FEASIBLE;
8150  for( c = 0; c < nconss; ++c )
8151  {
8152  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8153 
8154  if( isConsViolated(scip, conss[c]) )
8155  *result = SCIP_INFEASIBLE;
8156  }
8157 
8158  if( *result == SCIP_FEASIBLE )
8159  {
8160  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8162  return SCIP_OKAY;
8163  }
8164 
8165  SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8166  &minauxviol, &maxauxviol, &maxvarboundviol) );
8167 
8168  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8169  "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8170  SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8171  maxvarboundviol, SCIPgetLPFeastol(scip)); )
8172 
8173  assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8174 
8175  /* try to propagate */
8176  if( conshdlrdata->propinenforce )
8177  {
8178  SCIP_RESULT propresult;
8179  int nchgbds = 0;
8180 
8181  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8182 
8183  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8184  {
8185  *result = propresult;
8186  return SCIP_OKAY;
8187  }
8188  }
8189 
8190  /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8191  * all violated expr/auxvar in violated constraints)
8192  */
8193  if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8194  sol == NULL )
8195  {
8196  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8197  ++conshdlrdata->ntightenlp;
8198 
8199  *result = SCIP_SOLVELP;
8200 
8201  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8202  "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8203 
8204  return SCIP_OKAY;
8205  }
8206 
8207  /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8208  * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8209  */
8210  if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8211  {
8212  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8213  ++conshdlrdata->ntightenlp;
8214 
8215  *result = SCIP_SOLVELP;
8216 
8217  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8218 
8219  return SCIP_OKAY;
8220  }
8221 
8222  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8223 
8224  if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8225  *result == SCIP_INFEASIBLE )
8226  return SCIP_OKAY;
8227 
8228  assert(*result == SCIP_DIDNOTFIND);
8229 
8230  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8231  "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8232 
8233  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8234  {
8235  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8236  ++conshdlrdata->ntightenlp;
8237 
8238  *result = SCIP_SOLVELP;
8239 
8240  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8241  "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8242 
8243  return SCIP_OKAY;
8244  }
8245 
8246  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8247  SCIPgetLPFeastol(scip)) && sol == NULL )
8248  {
8249  /* try whether tighten the LP feasibility tolerance could help
8250  * maybe it is just some cut that hasn't been taken into account sufficiently
8251  * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8252  * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8253  * until the LP feastol reaches epsilon
8254  * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8255  * when maxauxviol is above LP feastol)
8256  */
8257  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8258  ++conshdlrdata->ndesperatetightenlp;
8259 
8260  *result = SCIP_SOLVELP;
8261 
8262  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8263 
8264  return SCIP_OKAY;
8265  }
8266 
8267  /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8268  if( !conshdlrdata->propinenforce )
8269  {
8270  SCIP_RESULT propresult;
8271  int nchgbds = 0;
8272 
8273  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8274 
8275  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8276  {
8277  *result = propresult;
8278  return SCIP_OKAY;
8279  }
8280  }
8281 
8282  /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8283  * now look if we find any unfixed variable that we could still branch on
8284  */
8285  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8286 
8287  if( nnotify > 0 )
8288  {
8289  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8290  ++conshdlrdata->ndesperatebranch;
8291 
8292  *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8293 
8294  return SCIP_OKAY;
8295  }
8296 
8297  /* if everything is fixed in violated constraints, then let's cut off the node
8298  * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8299  * result may not be conclusive (when constraint violations are small)
8300  * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8301  * sufficiently (see st_e40)
8302  * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8303  * not "desperate", but a pretty obvious thing to do
8304  */
8305  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8306  *result = SCIP_CUTOFF;
8307 
8308  /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8309  if( !SCIPisZero(scip, maxvarboundviol) )
8310  ++conshdlrdata->ndesperatecutoff;
8311 
8312  return SCIP_OKAY;
8313 }
8314 
8315 /** separation for all violated constraints to be used by SEPA callbacks */
8316 static
8318  SCIP* scip, /**< SCIP data structure */
8319  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8320  SCIP_CONS** conss, /**< constraints to process */
8321  int nconss, /**< number of constraints */
8322  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8323  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8324  )
8325 {
8326  SCIP_Longint soltag;
8327  SCIP_Bool haveviol = FALSE;
8328  int c;
8329 
8330  *result = SCIP_DIDNOTFIND;
8331 
8332  soltag = SCIPgetExprNewSoltag(scip);
8333 
8334  /* compute violations */
8335  for( c = 0; c < nconss; ++c )
8336  {
8337  assert(conss[c] != NULL);
8338 
8339  /* skip constraints that are not enabled, deleted, or have separation disabled */
8340  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8341  continue;
8342  assert(SCIPconsIsActive(conss[c]));
8343 
8344  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8345 
8346  if( isConsViolated(scip, conss[c]) )
8347  haveviol = TRUE;
8348  }
8349 
8350  /* if none of our constraints are violated, don't attempt separation */
8351  if( !haveviol )
8352  {
8353  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8354  return SCIP_OKAY;
8355  }
8356 
8357  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8358 
8359  /* call separation */
8360  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8361 
8362  return SCIP_OKAY;
8363 }
8364 
8365 /** hash key retrieval function for bilinear term entries */
8366 static
8367 SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8368 { /*lint --e{715}*/
8369  SCIP_CONSHDLRDATA* conshdlrdata;
8370  int idx;
8371 
8372  conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8373  assert(conshdlrdata != NULL);
8374 
8375  idx = ((int)(size_t)elem) - 1;
8376  assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8377 
8378  return (void*)&conshdlrdata->bilinterms[idx];
8379 }
8380 
8381 /** returns TRUE iff the bilinear term entries are equal */
8382 static
8383 SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8384 { /*lint --e{715}*/
8387 
8388  /* get corresponding entries */
8389  entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8390  entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8391  assert(entry1->x != NULL && entry1->y != NULL);
8392  assert(entry2->x != NULL && entry2->y != NULL);
8393  assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8394  assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8395 
8396  return entry1->x == entry2->x && entry1->y == entry2->y;
8397 }
8398 
8399 /** returns the hash value of the key */
8400 static
8401 SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8402 { /*lint --e{715}*/
8404 
8405  entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8406  assert(entry->x != NULL && entry->y != NULL);
8407  assert(SCIPvarCompare(entry->x, entry->y) < 1);
8408 
8409  return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8410 }
8411 
8412 /** compare two auxiliary expressions
8413  *
8414  * Compares auxiliary variables, followed by coefficients, and then constants.
8415  */
8416 static
8417 SCIP_DECL_SORTPTRCOMP(auxexprComp)
8421  int compvars;
8422  int i;
8423 
8424  /* compare the auxiliary variables */
8425  compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8426 
8427  if( compvars != 0 )
8428  return compvars;
8429 
8430  /* compare the coefficients and constants */
8431  for( i = 0; i < 3; ++i )
8432  {
8433  if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8434  return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8435  }
8436 
8437  return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8438 }
8439 
8440 /* add an auxiliary expression to a bilinear term */
8441 static
8443  SCIP* scip, /**< SCIP data structure */
8444  SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8445  SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8446  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8447  SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8448  )
8449 {
8450  SCIP_Bool found;
8451  int pos;
8452  int i;
8453 
8454  *added = FALSE;
8455 
8456  /* check if auxexpr has already been added to term */
8457  if( term->nauxexprs == 0 )
8458  {
8459  found = FALSE;
8460  pos = 0;
8461  }
8462  else
8463  {
8464  found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8465  }
8466 
8467  if( !found )
8468  {
8469  if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8470  return SCIP_OKAY;
8471 
8472  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8473  assert(term->auxexprssize >= term->nauxexprs + 1);
8474 
8475  /* insert expression at the correct position */
8476  for( i = term->nauxexprs; i > pos; --i )
8477  {
8478  term->aux.exprs[i] = term->aux.exprs[i-1];
8479  }
8480  term->aux.exprs[pos] = auxexpr;
8481  ++(term->nauxexprs);
8482  *added = TRUE;
8483  }
8484  else
8485  {
8486  term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8487  term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8488  }
8489 
8490  return SCIP_OKAY;
8491 }
8492 
8493 /** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8494 static
8496  SCIP* scip, /**< SCIP data structure */
8497  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8498  SCIP_CONS** conss, /**< nonlinear constraints */
8499  int nconss /**< total number of nonlinear constraints */
8500  )
8501 {
8502  SCIP_CONSHDLRDATA* conshdlrdata;
8503  SCIP_EXPRITER* it;
8504  int c;
8505 
8506  assert(conss != NULL || nconss == 0);
8507 
8508  if( nconss == 0 )
8509  return SCIP_OKAY;
8510 
8511  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8512  assert(conshdlrdata != NULL);
8513 
8514  /* check whether the bilinear terms have been stored already */
8515  if( conshdlrdata->bilinterms != NULL )
8516  return SCIP_OKAY;
8517 
8518  /* create and initialize iterator */
8519  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8522 
8523  /* iterate through all constraints */
8524  for( c = 0; c < nconss; ++c )
8525  {
8526  SCIP_CONSDATA* consdata;
8527  SCIP_EXPR* expr;
8528 
8529  assert(conss != NULL && conss[c] != NULL);
8530  consdata = SCIPconsGetData(conss[c]);
8531  assert(consdata != NULL);
8532 
8533  /* iterate through all expressions */
8534  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8535  {
8536  SCIP_EXPR** children = SCIPexprGetChildren(expr);
8537  SCIP_VAR* x = NULL;
8538  SCIP_VAR* y = NULL;
8539 
8540  /* check whether the expression is of the form f(..)^2 */
8541  if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8542  {
8543  x = SCIPgetExprAuxVarNonlinear(children[0]);
8544  y = x;
8545  }
8546  /* check whether the expression is of the form f(..) * g(..) */
8547  else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8548  {
8549  x = SCIPgetExprAuxVarNonlinear(children[0]);
8550  y = SCIPgetExprAuxVarNonlinear(children[1]);
8551  }
8552 
8553  /* add variables to the hash table */
8554  if( x != NULL && y != NULL )
8555  {
8558  }
8559  }
8560  }
8561 
8562  /* release iterator */
8563  SCIPfreeExpriter(&it);
8564 
8565  return SCIP_OKAY;
8566 }
8567 
8568 /** store x, y and the locks in a new bilinear term */
8569 static
8571  SCIP* scip, /**< SCIP data structure */
8572  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8573  SCIP_VAR* x, /**< the first variable */
8574  SCIP_VAR* y, /**< the second variable */
8575  int nlockspos, /**< number of positive locks of the bilinear term */
8576  int nlocksneg, /**< number of negative locks of the bilinear term */
8577  int* idx, /**< pointer to store the position of the term in bilinterms array */
8578  SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8579  )
8580 {
8581  SCIP_CONSHDLRDATA* conshdlrdata;
8583 
8584  assert(conshdlr != NULL);
8585  assert(x != NULL);
8586  assert(y != NULL);
8587  assert(nlockspos >= 0);
8588  assert(nlocksneg >= 0);
8589 
8590  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8591  assert(conshdlrdata != NULL);
8592 
8593  /* ensure that x.index <= y.index */
8594  if( SCIPvarCompare(x, y) == 1 )
8595  {
8596  SCIPswapPointers((void**)&x, (void**)&y);
8597  }
8598  assert(SCIPvarCompare(x, y) < 1);
8599 
8600  *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8601 
8602  /* update or create the term */
8603  if( *idx >= 0 )
8604  { /* the term has already been added */
8605  assert(conshdlrdata->bilinterms[*idx].x == x);
8606  assert(conshdlrdata->bilinterms[*idx].y == y);
8607 
8608  /* get term and add locks */
8609  term = &conshdlrdata->bilinterms[*idx];
8610  assert(existing <= term->existing); /* implicit terms are added after existing ones */
8611  term->nlockspos += nlockspos;
8612  term->nlocksneg += nlocksneg;
8613  }
8614  else
8615  { /* this is the first time we encounter this product */
8616  /* ensure size of bilinterms array */
8617  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8618 
8619  *idx = conshdlrdata->nbilinterms;
8620 
8621  /* get term and set values in the created bilinear term */
8622  term = &conshdlrdata->bilinterms[*idx];
8623  assert(term != NULL);
8624  term->x = x;
8625  term->y = y;
8626  term->nauxexprs = 0;
8627  term->auxexprssize = 0;
8628  term->nlockspos = nlockspos;
8629  term->nlocksneg = nlocksneg;
8630  term->existing = existing;
8631  if( existing )
8632  term->aux.var = NULL;
8633  else
8634  term->aux.exprs = NULL;
8635 
8636  /* increase the total number of bilinear terms */
8637  ++(conshdlrdata->nbilinterms);
8638 
8639  /* save to the hashtable */
8640  if( conshdlrdata->bilinhashtable == NULL )
8641  {
8642  SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8643  bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8644  (void*)conshdlrdata) );
8645  }
8646  assert(conshdlrdata->bilinhashtable != NULL);
8647 
8648  /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8649  * because zero can not be inserted into hash table
8650  */
8651  SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8652 
8653  /* capture product variables */
8654  SCIP_CALL( SCIPcaptureVar(scip, x) );
8655  SCIP_CALL( SCIPcaptureVar(scip, y) );
8656  }
8657 
8658  return SCIP_OKAY;
8659 }
8660 
8661 /** frees array of bilinear terms and hash table */
8662 static
8664  SCIP* scip, /**< SCIP data structure */
8665  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8666  )
8667 {
8668  int i;
8669  int j;
8670 
8671  assert(conshdlrdata != NULL);
8672 
8673  /* check whether bilinear terms have been stored */
8674  if( conshdlrdata->bilinterms == NULL )
8675  {
8676  assert(conshdlrdata->bilinterms == NULL);
8677  assert(conshdlrdata->nbilinterms == 0);
8678  assert(conshdlrdata->bilintermssize == 0);
8679 
8680  return SCIP_OKAY;
8681  }
8682 
8683  /* release variables */
8684  for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8685  {
8686  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8687  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8688 
8689  for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8690  {
8691  if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8692  {
8693  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8694  }
8695  SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8696  }
8697 
8698  if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8699  {
8700  SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8701  continue;
8702  }
8703 
8704  /* the rest is for simple terms with a single auxvar */
8705 
8706  /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8707  if( conshdlrdata->bilinterms[i].aux.var != NULL )
8708  {
8709  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8710  }
8711  }
8712 
8713  /* free hash table */
8714  if( conshdlrdata->bilinhashtable != NULL )
8715  {
8716  SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8717  }
8718 
8719  /* free bilinterms array; reset counters */
8720  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8721  conshdlrdata->nbilinterms = 0;
8722  conshdlrdata->bilintermssize = 0;
8723 
8724  return SCIP_OKAY;
8725 }
8726 
8727 /*
8728  * vertex polyhedral separation
8729  */
8730 
8731 /** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8732 static
8734  SCIP* scip, /**< SCIP data structure */
8735  int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
8736  SCIP_LPI** lp /**< pointer to store created LP */
8737  )
8738 {
8739  SCIP_Real* obj;
8740  SCIP_Real* lb;
8741  SCIP_Real* ub;
8742  SCIP_Real* val;
8743  int* beg;
8744  int* ind;
8745  unsigned int nnonz;
8746  unsigned int ncols;
8747  unsigned int nrows;
8748  unsigned int i;
8749  unsigned int k;
8750 
8751  assert(scip != NULL);
8752  assert(lp != NULL);
8753  assert(nvars > 0);
8754  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8755 
8756  SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8757 
8758  /* create lpi to store the LP */
8759  SCIP_CALL( SCIPlpiCreate(lp, SCIPgetMessagehdlr(scip), "facet finding LP", SCIP_OBJSEN_MINIMIZE) );
8760 
8761  nrows = (unsigned int)nvars + 1;
8762  ncols = POWEROFTWO((unsigned int)nvars);
8763  nnonz = (ncols * (nrows + 1)) / 2;
8764 
8765  /* allocate necessary memory; set obj, lb, and ub to zero */
8766  SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
8767  SCIP_CALL( SCIPallocClearBufferArray(scip, &lb, ncols) );
8768  SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8769  SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8770  SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8771  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8772 
8773  /* calculate nonzero entries in the LP */
8774  for( i = 0, k = 0; i < ncols; ++i )
8775  {
8776  int row;
8777  unsigned int a;
8778 
8779  /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8780  ub[i] = SCIPlpiInfinity(*lp);
8781 
8782  SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8783  beg[i] = (int)k;
8784  row = 0;
8785 
8786  /* iterate through the bit representation of i */
8787  a = 1;
8788  while( a <= i )
8789  {
8790  if( (a & i) != 0 )
8791  {
8792  val[k] = 1.0;
8793  ind[k] = row;
8794 
8795  SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
8796 
8797  ++k;
8798  }
8799 
8800  a <<= 1;
8801  ++row;
8802  assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8803  assert(POWEROFTWO(row) == a);
8804  }
8805 
8806  /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8807  val[k] = 1.0;
8808  ind[k] = (int)nrows - 1;
8809  ++k;
8810  SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
8811  }
8812  assert(k == nnonz);
8813 
8814  /* load all data into LP interface
8815  * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8816  */
8817  assert(nrows <= ncols);
8819  (int)ncols, obj, lb, ub, NULL,
8820  (int)nrows, lb, lb, NULL,
8821  (int)nnonz, beg, ind, val) );
8822 
8823  /* for the last row, we can set the rhs to 1.0 already */
8824  ind[0] = (int)nrows - 1;
8825  val[0] = 1.0;
8826  SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8827 
8828  /* free allocated memory */
8829  SCIPfreeBufferArray(scip, &ind);
8830  SCIPfreeBufferArray(scip, &val);
8831  SCIPfreeBufferArray(scip, &beg);
8832  SCIPfreeBufferArray(scip, &ub);
8833  SCIPfreeBufferArray(scip, &lb);
8834  SCIPfreeBufferArray(scip, &obj);
8835 
8836  return SCIP_OKAY;
8837 }
8838 
8839 /** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8840  * \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
8841  * set of vertices of the domain
8842  */
8843 static
8845  SCIP* scip, /**< SCIP data structure */
8846  SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
8847  SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8848  SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
8849  int nallvars, /**< number of all variables */
8850  int nvars, /**< number of unfixed variables */
8851  int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
8852  SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
8853  SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
8854  )
8855 {
8856  SCIP_Real maxerror;
8857  SCIP_Real facetval;
8858  SCIP_Real funval;
8859  SCIP_Real error;
8860  unsigned int i;
8861  unsigned int ncorners;
8862  unsigned int prev;
8863 
8864  assert(scip != NULL);
8865  assert(funvals != NULL);
8866  assert(box != NULL);
8867  assert(nonfixedpos != NULL);
8868  assert(facetcoefs != NULL);
8869 
8870  ncorners = POWEROFTWO(nvars);
8871  maxerror = 0.0;
8872 
8873  /* check the origin (all variables at lower bound) */
8874  facetval = facetconstant;
8875  for( i = 0; i < (unsigned int) nallvars; ++i )
8876  facetval += facetcoefs[i] * box[2*i];
8877 
8878  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8879  funval = funvals[0];
8880  if( overestimate )
8881  error = funval - facetval;
8882  else
8883  error = facetval - funval;
8884 
8885  /* update maximum error */
8886  maxerror = MAX(error, maxerror);
8887 
8888  prev = 0;
8889  for( i = 1; i < ncorners; ++i )
8890  {
8891  unsigned int gray;
8892  unsigned int diff;
8893  unsigned int pos;
8894  int origpos;
8895 
8896  gray = i ^ (i >> 1);
8897  diff = gray ^ prev;
8898 
8899  /* compute position of unique 1 of diff */
8900  pos = 0;
8901  while( (diff >>= 1) != 0 )
8902  ++pos;
8903  assert(pos < (unsigned int)nvars);
8904 
8905  origpos = nonfixedpos[pos];
8906 
8907  if( gray > prev )
8908  facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8909  else
8910  facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8911 
8912  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8913  funval = funvals[gray];
8914  if( overestimate )
8915  error = funval - facetval;
8916  else
8917  error = facetval - funval;
8918 
8919  /* update maximum error */
8920  maxerror = MAX(error, maxerror);
8921 
8922  prev = gray;
8923  }
8924 
8925  SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8926 
8927  return maxerror;
8928 }
8929 
8930 /** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
8931 static
8933  SCIP* scip, /**< SCIP data structure */
8934  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8935  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8936  SCIP_Real* xstar, /**< point to be separated */
8937  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8938  int nallvars, /**< half of the length of box */
8939  int* nonfixedpos, /**< indices of nonfixed variables */
8940  SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
8941  int nvars, /**< number of nonfixed variables */
8942  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
8943  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
8944  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8945  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
8946  )
8947 { /*lint --e{715}*/
8948  SCIP_CONSHDLRDATA* conshdlrdata;
8949  SCIP_LPI* lp;
8950  SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8951  int* inds;
8952  int ncols;
8953  int nrows;
8954  int i;
8955  SCIP_Real facetvalue;
8956  SCIP_Real mindomwidth;
8957  SCIP_RETCODE lpsolveretcode;
8958 
8959  assert(scip != NULL);
8960  assert(conshdlr != NULL);
8961  assert(xstar != NULL);
8962  assert(box != NULL);
8963  assert(nonfixedpos != NULL);
8964  assert(funvals != NULL);
8965  assert(nvars >= 0);
8966  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8967  assert(success != NULL);
8968  assert(facetcoefs != NULL);
8969  assert(facetconstant != NULL);
8970 
8971  *success = FALSE;
8972 
8973  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8974  assert(conshdlrdata != NULL);
8975 
8976  if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8977  {
8978  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8979  }
8980 
8981  /* construct an LP for this size, if not having one already */
8982  if( conshdlrdata->vp_lp[nvars] == NULL )
8983  {
8984  SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8985  }
8986  lp = conshdlrdata->vp_lp[nvars];
8987  assert(lp != NULL);
8988 
8989  /* get number of cols and rows of separation lp */
8990  SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8991  SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8992 
8993  /* number of columns should equal the number of corners = 2^nvars */
8994  assert(ncols == (int)POWEROFTWO(nvars));
8995 
8996  /* allocate necessary memory */
8997  SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8998  SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8999 
9000  /*
9001  * set up the described LP on the transformed space
9002  */
9003 
9004  for( i = 0; i < ncols; ++i )
9005  inds[i] = i;
9006 
9007  /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9008  mindomwidth = 2*SCIPinfinity(scip);
9009  for( i = 0; i < nrows-1; ++i )
9010  {
9011  SCIP_Real solval;
9012  SCIP_Real lb;
9013  SCIP_Real ub;
9014  int varpos;
9015 
9016  assert(i < nvars);
9017 
9018  varpos = nonfixedpos[i];
9019  lb = box[2 * varpos];
9020  ub = box[2 * varpos + 1];
9021  solval = xstar[varpos];
9022 
9023  if( ub - lb < mindomwidth )
9024  mindomwidth = ub - lb;
9025 
9026  /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9027  if( solval <= lb )
9028  aux[i] = 0.0;
9029  else if( solval >= ub )
9030  aux[i] = 1.0;
9031  else
9032  aux[i] = (solval - lb) / (ub - lb);
9033 
9034  /* perturb point to hopefully obtain a facet of the convex envelope */
9035  if( conshdlrdata->vp_maxperturb > 0.0 )
9036  {
9037  assert(conshdlrdata->vp_randnumgen != NULL);
9038 
9039  if( aux[i] == 1.0 )
9040  aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9041  else if( aux[i] == 0.0 )
9042  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9043  else
9044  {
9045  SCIP_Real perturbation;
9046 
9047  perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9048  perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9049  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9050  }
9051  assert(0.0 < aux[i] && aux[i] < 1.0);
9052  }
9053 
9054  SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9055  }
9056 
9057  /* update LP */
9058  SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9059  SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9061 
9062  /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9063  if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9064  {
9065  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9066  }
9067  /* set an iteration limit so we do not run forever */
9068  SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPITLIM, 100*ncols) );
9069  /* 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 */
9071  /* since we work with the dual of the LP, dual feastol determines validity of the facet
9072  * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9073  * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9074  */
9075  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, MIN(SCIPfeastol(scip), MAX(SCIPepsilon(scip), mindomwidth * SCIPfeastol(scip)))) );
9076 
9077 #ifdef SCIP_DEBUG
9079 #endif
9080 
9081  /*
9082  * solve the LP and store the resulting facet for the transformed space
9083  */
9084  if( conshdlrdata->vp_dualsimplex )
9085  {
9086  lpsolveretcode = SCIPlpiSolveDual(lp);
9087  }
9088  else
9089  {
9090  lpsolveretcode = SCIPlpiSolvePrimal(lp);
9091  }
9092  if( lpsolveretcode == SCIP_LPERROR )
9093  {
9094  SCIPdebugMsg(scip, "LP error, aborting.\n");
9095  goto CLEANUP;
9096  }
9097  SCIP_CALL( lpsolveretcode );
9098 
9099  /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9100  if( !SCIPlpiIsDualFeasible(lp) )
9101  {
9102  SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9103  goto CLEANUP;
9104  }
9105 
9106  /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9107  * columns than needed, in particular, \bar \beta is the last dual multiplier
9108  */
9109  SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9110 
9111  for( i = 0; i < nvars; ++i )
9112  facetcoefs[nonfixedpos[i]] = aux[i];
9113  /* last dual multiplier is the constant */
9114  *facetconstant = aux[nrows - 1];
9115 
9116 #ifdef SCIP_DEBUG
9117  SCIPdebugMsg(scip, "facet for the transformed problem: ");
9118  for( i = 0; i < nallvars; ++i )
9119  {
9120  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9121  }
9122  SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9123 #endif
9124 
9125  /*
9126  * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9127  */
9128 
9129  SCIPdebugMsg(scip, "facet in orig. space: ");
9130 
9131  facetvalue = 0.0;
9132  for( i = 0; i < nvars; ++i )
9133  {
9134  SCIP_Real lb;
9135  SCIP_Real ub;
9136  int varpos;
9137 
9138  varpos = nonfixedpos[i];
9139  lb = box[2 * varpos];
9140  ub = box[2 * varpos + 1];
9141  assert(!SCIPisEQ(scip, lb, ub));
9142 
9143  /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9144  facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9145 
9146  /* beta = beta_bar - sum_i alpha_i * lb_i */
9147  *facetconstant -= facetcoefs[varpos] * lb;
9148 
9149  /* evaluate */
9150  facetvalue += facetcoefs[varpos] * xstar[varpos];
9151 
9152  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9153  }
9154  SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9155 
9156  /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9157  facetvalue += *facetconstant;
9158 
9159  SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9160 
9161  /* if overestimate, then we want facetvalue < targetvalue
9162  * if underestimate, then we want facetvalue > targetvalue
9163  * if none holds, give up
9164  * so maybe here we should check against the minimal violation
9165  */
9166  if( overestimate == (facetvalue > targetvalue) )
9167  {
9168  SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9169  goto CLEANUP;
9170  }
9171 
9172  /* if we made it until here, then we have a nice facet */
9173  *success = TRUE;
9174 
9175 CLEANUP:
9176  /* free allocated memory */
9177  SCIPfreeBufferArray(scip, &inds);
9178  SCIPfreeBufferArray(scip, &aux);
9179 
9180  return SCIP_OKAY;
9181 }
9182 
9183 /** computes a facet of the convex or concave envelope of a univariant vertex polyhedral function
9184  *
9185  * In other words, compute the line that passes through two given points.
9186  */
9187 static
9189  SCIP* scip, /**< SCIP data structure */
9190  SCIP_Real left, /**< left coordinate */
9191  SCIP_Real right, /**< right coordinate */
9192  SCIP_Real funleft, /**< value of function in left coordinate */
9193  SCIP_Real funright, /**< value of function in right coordinate */
9194  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9195  SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9196  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9197  )
9198 {
9199  assert(scip != NULL);
9200  assert(SCIPisLE(scip, left, right));
9201  assert(!SCIPisInfinity(scip, -left));
9202  assert(!SCIPisInfinity(scip, right));
9203  assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9204  assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9205  assert(success != NULL);
9206  assert(facetcoef != NULL);
9207  assert(facetconstant != NULL);
9208 
9209  *facetcoef = (funright - funleft) / (right - left);
9210  *facetconstant = funleft - *facetcoef * left;
9211 
9212  *success = TRUE;
9213 
9214  return SCIP_OKAY;
9215 }
9216 
9217 /** given three points, constructs coefficient of equation for hyperplane generated by these three points
9218  *
9219  * Three points a, b, and c are given.
9220  * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9221  * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9222  */
9223 static
9225  SCIP* scip, /**< SCIP data structure */
9226  SCIP_Real a1, /**< first coordinate of a */
9227  SCIP_Real a2, /**< second coordinate of a */
9228  SCIP_Real a3, /**< third coordinate of a */
9229  SCIP_Real b1, /**< first coordinate of b */
9230  SCIP_Real b2, /**< second coordinate of b */
9231  SCIP_Real b3, /**< third coordinate of b */
9232  SCIP_Real c1, /**< first coordinate of c */
9233  SCIP_Real c2, /**< second coordinate of c */
9234  SCIP_Real c3, /**< third coordinate of c */
9235  SCIP_Real* alpha, /**< coefficient of first coordinate */
9236  SCIP_Real* beta, /**< coefficient of second coordinate */
9237  SCIP_Real* gamma_, /**< coefficient of third coordinate */
9238  SCIP_Real* delta /**< constant right-hand side */
9239  )
9240 {
9241  assert(scip != NULL);
9242  assert(alpha != NULL);
9243  assert(beta != NULL);
9244  assert(gamma_ != NULL);
9245  assert(delta != NULL);
9246 
9247  *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9248  *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9249  *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9250  *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9251 
9252  /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9253 
9254  if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9255  SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9256  SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9257  {
9258  SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9259  *delta = 0.0;
9260  *alpha = 0.0;
9261  *beta = 0.0;
9262  *gamma_ = 0.0;
9263  return SCIP_OKAY;
9264  }
9265 
9266  /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9267  if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9268  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9269  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9270  {
9271  SCIP_Real m[9];
9272  SCIP_Real rhs[3];
9273  SCIP_Real x[3];
9274  SCIP_Bool success;
9275 
9276  /*
9277  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));
9278  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));
9279  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));
9280  */
9281 
9282  /* initialize matrix column-wise */
9283  m[0] = a1;
9284  m[1] = b1;
9285  m[2] = c1;
9286  m[3] = a2;
9287  m[4] = b2;
9288  m[5] = c2;
9289  m[6] = a3;
9290  m[7] = b3;
9291  m[8] = c3;
9292 
9293  rhs[0] = 1.0;
9294  rhs[1] = 1.0;
9295  rhs[2] = 1.0;
9296 
9297  SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9298 
9299  /* solve the linear problem */
9300  SCIP_CALL( SCIPsolveLinearEquationsIpopt(3, m, rhs, x, &success) );
9301 
9302  *delta = rhs[0];
9303  *alpha = x[0];
9304  *beta = x[1];
9305  *gamma_ = x[2];
9306 
9307  /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9308  * not add a cut to SCIP and that all assertions are trivially fulfilled
9309  */
9310  if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9311  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9312  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9313  {
9314  SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9315  *delta = 0.0;
9316  *alpha = 0.0;
9317  *beta = 0.0;
9318  *gamma_ = 0.0;
9319  }
9320  }
9321 
9322  if( *gamma_ < 0.0 )
9323  {
9324  *alpha = -*alpha;
9325  *beta = -*beta;
9326  *gamma_ = -*gamma_;
9327  *delta = -*delta;
9328  }
9329 
9330  return SCIP_OKAY;
9331 }
9332 
9333 /** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9334 static
9336  SCIP* scip, /**< SCIP data structure */
9337  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9338  SCIP_Real p1[2], /**< first vertex of box */
9339  SCIP_Real p2[2], /**< second vertex of box */
9340  SCIP_Real p3[2], /**< third vertex of box */
9341  SCIP_Real p4[2], /**< forth vertex of box */
9342  SCIP_Real p1val, /**< value in p1 */
9343  SCIP_Real p2val, /**< value in p2 */
9344  SCIP_Real p3val, /**< value in p3 */
9345  SCIP_Real p4val, /**< value in p4 */
9346  SCIP_Real xstar[2], /**< point to be separated */
9347  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9348  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9349  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9350  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9351  )
9352 {
9353  SCIP_Real alpha, beta, gamma_, delta;
9354  SCIP_Real xstarval, candxstarval = 0.0;
9355  int leaveout;
9356 
9357  assert(scip != NULL);
9358  assert(success != NULL);
9359  assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9360  assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9361  assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9362  assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9363  assert(facetcoefs != NULL);
9364  assert(facetconstant != NULL);
9365 
9366  *success = FALSE;
9367 
9368  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9369  if( !overestimate )
9370  {
9371  p1val = -p1val;
9372  p2val = -p2val;
9373  p3val = -p3val;
9374  p4val = -p4val;
9375  targetvalue = -targetvalue;
9376  }
9377 
9378  SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9379  SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9380  SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9381  SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9382 
9383  /* Compute coefficients alpha, beta, gamma (>0), delta such that
9384  * alpha*x + beta*y + gamma*z = delta
9385  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9386  * the fourth corner point lies below this hyperplane.
9387  * 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.,
9388  * alpha*x + beta*y - delta <= -gamma * f(x,y),
9389  * or, equivalently,
9390  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9391  */
9392  for( leaveout = 1; leaveout <= 4; ++leaveout )
9393  {
9394  switch( leaveout)
9395  {
9396  case 1 :
9397  /* get hyperplane through p2, p3, p4 */
9398  SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9399  &alpha, &beta, &gamma_, &delta) );
9400  /* if not underestimating in p1, then go to next candidate */
9401  if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9402  continue;
9403  break;
9404 
9405  case 2 :
9406  /* get hyperplane through p1, p3, p4 */
9407  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9408  &alpha, &beta, &gamma_, &delta) );
9409  /* if not underestimating in p2, then go to next candidate */
9410  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9411  continue;
9412  break;
9413 
9414  case 3 :
9415  /* get hyperplane through p1, p2, p4 */
9416  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9417  &alpha, &beta, &gamma_, &delta) );
9418  /* if not underestimating in p3, then go to next candidate */
9419  if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9420  continue;
9421  break;
9422 
9423  case 4 :
9424  /* get hyperplane through p1, p2, p3 */
9425  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9426  &alpha, &beta, &gamma_, &delta) );
9427  /* if not underestimating in p4, then stop */
9428  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9429  continue;
9430  break;
9431 
9432  default: /* only for lint */
9433  alpha = SCIP_INVALID;
9434  beta = SCIP_INVALID;
9435  gamma_ = SCIP_INVALID;
9436  delta = SCIP_INVALID;
9437  break;
9438  }
9439 
9440  /* check if bad luck: should not happen if numerics are fine */
9441  if( SCIPisZero(scip, gamma_) )
9442  continue;
9443  assert(!SCIPisNegative(scip, gamma_));
9444 
9445  /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9446  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9447  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9448  continue;
9449 
9450  SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9451 
9452  /* value of hyperplane candidate in xstar */
9453  xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9454 
9455  /* if reaching target and first or better than previous candidate, then update */
9456  if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9457  {
9458  /* flip hyperplane */
9459  if( !overestimate )
9460  gamma_ = -gamma_;
9461 
9462  facetcoefs[0] = -alpha/gamma_;
9463  facetcoefs[1] = -beta/gamma_;
9464  *facetconstant = delta/gamma_;
9465 
9466  *success = TRUE;
9467  candxstarval = xstarval;
9468  }
9469  }
9470 
9471  return SCIP_OKAY;
9472 }
9473 
9474 /*
9475  * Callback methods of constraint handler
9476  */
9477 
9478 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
9479 static
9480 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
9481 { /*lint --e{715}*/
9482  SCIP_CONSHDLR* targetconshdlr;
9483  SCIP_CONSHDLRDATA* sourceconshdlrdata;
9484  int i;
9485 
9486  assert(scip != NULL);
9487  assert(conshdlr != NULL);
9488  assert(valid != NULL);
9489  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
9490 
9491  /* create basic data of constraint handler and include it to scip */
9493 
9494  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9495  assert(targetconshdlr != NULL);
9496  assert(targetconshdlr != conshdlr);
9497 
9498  sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
9499  assert(sourceconshdlrdata != NULL);
9500 
9501  /* copy nonlinear handlers */
9502  for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
9503  {
9504  SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
9505  }
9506 
9507  *valid = TRUE;
9508 
9509  return SCIP_OKAY;
9510 }
9511 
9512 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9513 static
9514 SCIP_DECL_CONSFREE(consFreeNonlinear)
9515 { /*lint --e{715}*/
9516  SCIP_CONSHDLRDATA* conshdlrdata;
9517  int i;
9518 
9519  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9520  assert(conshdlrdata != NULL);
9521 
9522  /* free nonlinear handlers */
9523  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9524  {
9525  SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
9526  assert(conshdlrdata->nlhdlrs[i] == NULL);
9527  }
9528  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
9529  conshdlrdata->nlhdlrssize = 0;
9530 
9531  /* free upgrade functions */
9532  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
9533  {
9534  assert(conshdlrdata->consupgrades[i] != NULL);
9535  SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
9536  }
9537  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
9538 
9539  SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
9540 
9541  SCIPqueueFree(&conshdlrdata->reversepropqueue);
9542 
9543  if( conshdlrdata->vp_randnumgen != NULL )
9544  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9545 
9546  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9547  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9548  {
9549  if( conshdlrdata->vp_lp[i] != NULL )
9550  {
9551  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9552  }
9553  }
9554 
9555  assert(conshdlrdata->branchrandnumgen == NULL);
9556 
9557  assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
9558  SCIPhashmapFree(&conshdlrdata->var2expr);
9559 
9560  SCIPfreeBlockMemory(scip, &conshdlrdata);
9561  SCIPconshdlrSetData(conshdlr, NULL);
9562 
9563  return SCIP_OKAY;
9564 }
9565 
9566 
9567 /** initialization method of constraint handler (called after problem was transformed) */
9568 static
9569 SCIP_DECL_CONSINIT(consInitNonlinear)
9570 { /*lint --e{715}*/
9571  SCIP_CONSHDLRDATA* conshdlrdata;
9572  int i;
9573 
9574  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9575  assert(conshdlrdata != NULL);
9576 
9577  /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
9578  conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
9579  /* set to 1 so it is larger than initial value of lastenforound in exprs */
9580  conshdlrdata->enforound = 1;
9581  /* reset numbering for auxiliary variables */
9582  conshdlrdata->auxvarid = 0;
9583 
9584  for( i = 0; i < nconss; ++i )
9585  {
9586  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
9587  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
9588  }
9589 
9590  /* sort nonlinear handlers by detection priority, in decreasing order */
9591  if( conshdlrdata->nnlhdlrs > 1 )
9592  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
9593 
9594  /* get heuristics for later use */
9595  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9596  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9597 
9598  /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
9599  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9600  {
9601  SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
9602  }
9603 
9604  /* reset statistics in constraint handler */
9605  conshdlrdata->nweaksepa = 0;
9606  conshdlrdata->ntightenlp = 0;
9607  conshdlrdata->ndesperatebranch = 0;
9608  conshdlrdata->ndesperatecutoff = 0;
9609  conshdlrdata->ndesperatetightenlp = 0;
9610  conshdlrdata->nforcelp = 0;
9611  SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
9612  conshdlrdata->ncanonicalizecalls = 0;
9613 
9614 #ifdef ENFOLOGFILE
9615  ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
9616 #endif
9617 
9618  return SCIP_OKAY;
9619 }
9620 
9621 
9622 /** deinitialization method of constraint handler (called before transformed problem is freed) */
9623 static
9624 SCIP_DECL_CONSEXIT(consExitNonlinear)
9625 { /*lint --e{715}*/
9626  SCIP_CONSHDLRDATA* conshdlrdata;
9627  SCIP_CONS** consssorted;
9628  int i;
9629 
9630  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9631  assert(conshdlrdata != NULL);
9632 
9633  if( nconss > 0 )
9634  {
9635  /* for better performance of dropVarEvents, we sort by index, descending */
9636  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
9637  SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
9638 
9639  for( i = 0; i < nconss; ++i )
9640  {
9641  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
9642  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
9643  }
9644 
9645  SCIPfreeBufferArray(scip, &consssorted);
9646  }
9647 
9648  conshdlrdata->subnlpheur = NULL;
9649  conshdlrdata->trysolheur = NULL;
9650 
9651  if( conshdlrdata->vp_randnumgen != NULL )
9652  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9653 
9654  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9655  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9656  {
9657  if( conshdlrdata->vp_lp[i] != NULL )
9658  {
9659  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9660  }
9661  }
9662 
9663  if( conshdlrdata->branchrandnumgen != NULL )
9664  SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
9665 
9666  /* deinitialize nonlinear handlers */
9667  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9668  {
9669  SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
9670  }
9671 
9672  ENFOLOG(
9673  if( enfologfile != NULL )
9674  {
9675  fclose(enfologfile);
9676  enfologfile = NULL;
9677  })
9678 
9679  return SCIP_OKAY;
9680 }
9681 
9682 
9683 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
9684 #ifdef SCIP_DISABLED_CODE
9685 static
9687 { /*lint --e{715}*/
9688  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
9689  SCIPABORT(); /*lint --e{527}*/
9690 
9691  return SCIP_OKAY;
9692 }
9693 #else
9694 #define consInitpreNonlinear NULL
9695 #endif
9696 
9697 
9698 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9699 static
9700 SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
9701 { /*lint --e{715}*/
9702  SCIP_Bool infeasible;
9703 
9704  if( nconss == 0 )
9705  return SCIP_OKAY;
9706 
9707  /* skip some extra work if already known to be infeasible */
9708  if( SCIPgetStatus(scip) == SCIP_STATUS_INFEASIBLE )
9709  return SCIP_OKAY;
9710 
9711  /* simplify constraints and replace common subexpressions */
9712  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
9713 
9714  /* currently SCIP does not offer to communicate this,
9715  * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
9716  * or if a constraint expression became constant
9717  * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
9718  */
9719  /* assert(!infeasible); */
9720 
9721  /* tell SCIP that we have something nonlinear */
9722  SCIPenableNLP(scip);
9723 
9724  return SCIP_OKAY;
9725 }
9726 
9727 
9728 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
9729 static
9730 SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
9731 { /*lint --e{715}*/
9732  SCIP_CONSHDLRDATA* conshdlrdata;
9733  int i;
9734 
9735  /* skip remaining initializations if we have solved already
9736  * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
9737  * assumes nonempty activities in expressions
9738  */
9739  switch( SCIPgetStatus(scip) )
9740  {
9741  case SCIP_STATUS_OPTIMAL:
9743  case SCIP_STATUS_UNBOUNDED:
9744  case SCIP_STATUS_INFORUNBD:
9745  return SCIP_OKAY;
9746  default: ;
9747  } /*lint !e788 */
9748 
9749  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9750  assert(conshdlrdata != NULL);
9751 
9752  /* reset one of the number of detections counter to count only current round */
9753  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9754  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
9755 
9756  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
9757 
9758  /* catch new solution event */
9759  if( nconss != 0 && conshdlrdata->linearizeheursol != 'o' )
9760  {
9761  SCIP_EVENTHDLR* eventhdlr;
9762 
9763  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9764  assert(eventhdlr != NULL);
9765 
9766  SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
9767  eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9768  }
9769 
9770  /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
9771  if( conshdlrdata->branchpscostweight > 0.0 )
9772  {
9773  SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
9774  if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
9775  {
9776  SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
9777  SCIPABORT();
9778  return SCIP_INVALIDDATA;
9779  }
9780  }
9781 
9782  return SCIP_OKAY;
9783 }
9784 
9785 
9786 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9787 static
9788 SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
9789 { /*lint --e{715}*/
9790  SCIP_CONSHDLRDATA* conshdlrdata;
9791 
9792  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
9793 
9794  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9795  assert(conshdlrdata != NULL);
9796 
9797  /* free hash table for bilinear terms */
9798  SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
9799 
9800  /* reset flag to allow another call of presolSingleLockedVars() after a restart */
9801  conshdlrdata->checkedvarlocks = FALSE;
9802 
9803  /* drop catching new solution event, if catched before */
9804  if( conshdlrdata->newsoleventfilterpos >= 0 )
9805  {
9806  SCIP_EVENTHDLR* eventhdlr;
9807 
9808  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9809  assert(eventhdlr != NULL);
9810 
9811  SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9812  conshdlrdata->newsoleventfilterpos = -1;
9813  }
9814 
9815  return SCIP_OKAY;
9816 }
9817 
9818 
9819 /** frees specific constraint data */
9820 static
9821 SCIP_DECL_CONSDELETE(consDeleteNonlinear)
9822 { /*lint --e{715}*/
9823  assert(consdata != NULL);
9824  assert(*consdata != NULL);
9825  assert((*consdata)->expr != NULL);
9826 
9827  /* constraint locks should have been removed */
9828  assert((*consdata)->nlockspos == 0);
9829  assert((*consdata)->nlocksneg == 0);
9830 
9831  /* free variable expressions */
9832  SCIP_CALL( freeVarExprs(scip, *consdata) );
9833 
9834  SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
9835 
9836  /* free nonlinear row representation */
9837  if( (*consdata)->nlrow != NULL )
9838  {
9839  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
9840  }
9841 
9842  SCIPfreeBlockMemory(scip, consdata);
9843 
9844  return SCIP_OKAY;
9845 }
9846 
9847 
9848 /** transforms constraint data into data belonging to the transformed problem */
9849 static
9850 SCIP_DECL_CONSTRANS(consTransNonlinear)
9851 { /*lint --e{715}*/
9852  SCIP_EXPR* targetexpr;
9853  SCIP_CONSDATA* sourcedata;
9854 
9855  sourcedata = SCIPconsGetData(sourcecons);
9856  assert(sourcedata != NULL);
9857 
9858  /* get a copy of sourceexpr with transformed vars */
9859  SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
9860  assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
9861 
9862  /* create transformed cons (only captures targetexpr, no need to copy again) */
9863  SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
9864  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
9865  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
9866  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
9867  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
9868  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
9869 
9870  /* release target expr */
9871  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
9872 
9873  return SCIP_OKAY;
9874 }
9875 
9876 
9877 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9878 static
9879 SCIP_DECL_CONSINITLP(consInitlpNonlinear)
9880 { /*lint --e{715}*/
9881  /* create auxiliary variables and call separation initialization callbacks of the expression handlers
9882  * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
9883  * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
9884  * for now, there is an assert in detectNlhdlrs to require initial if separated
9885  */
9886  SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
9887 
9888  /* collect all bilinear terms for which an auxvar is present
9889  * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
9890  * addition (and removal?) of constraints during solve
9891  * this is typically the majority of constraints, but the method should be made more flexible
9892  */
9893  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
9894 
9895  return SCIP_OKAY;
9896 }
9897 
9898 
9899 /** separation method of constraint handler for LP solutions */
9900 static
9901 SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
9902 { /*lint --e{715}*/
9903  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
9904 
9905  return SCIP_OKAY;
9906 }
9907 
9908 
9909 /** separation method of constraint handler for arbitrary primal solutions */
9910 static
9911 SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
9912 { /*lint --e{715}*/
9913  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
9914 
9915  return SCIP_OKAY;
9916 }
9917 
9918 
9919 /** constraint enforcing method of constraint handler for LP solutions */
9920 static
9921 SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
9922 { /*lint --e{715}*/
9923  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
9924 
9925  return SCIP_OKAY;
9926 }
9927 
9928 
9929 /** constraint enforcing method of constraint handler for relaxation solutions */
9930 static
9931 SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
9932 { /*lint --e{715}*/
9933  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
9934 
9935  return SCIP_OKAY;
9936 }
9937 
9938 
9939 /** constraint enforcing method of constraint handler for pseudo solutions */
9940 static
9941 SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
9942 { /*lint --e{715}*/
9943  SCIP_RESULT propresult;
9944  SCIP_Longint soltag;
9945  int nchgbds;
9946  int nnotify;
9947  int c;
9948 
9949  soltag = SCIPgetExprNewSoltag(scip);
9950 
9951  *result = SCIP_FEASIBLE;
9952  for( c = 0; c < nconss; ++c )
9953  {
9954  SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
9955 
9956  if( isConsViolated(scip, conss[c]) )
9957  *result = SCIP_INFEASIBLE;
9958  }
9959 
9960  if( *result == SCIP_FEASIBLE )
9961  return SCIP_OKAY;
9962 
9963  /* try to propagate
9964  * TODO obey propinenfo parameter, but we need something to recognize cutoff
9965  */
9966  nchgbds = 0;
9967  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
9968 
9969  if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
9970  {
9971  *result = propresult;
9972  return SCIP_OKAY;
9973  }
9974 
9975  /* register all unfixed variables in all violated constraints as branching candidates */
9976  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
9977  if( nnotify > 0 )
9978  {
9979  SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
9980 
9981  return SCIP_OKAY;
9982  }
9983 
9984  SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
9985  *result = SCIP_SOLVELP;
9986  ++SCIPconshdlrGetData(conshdlr)->nforcelp;
9987 
9988  return SCIP_OKAY;
9989 }
9990 
9991 
9992 /** feasibility check method of constraint handler for integral solutions */
9993 static
9994 SCIP_DECL_CONSCHECK(consCheckNonlinear)
9995 { /*lint --e{715}*/
9996  SCIP_CONSHDLRDATA* conshdlrdata;
9997  SCIP_CONSDATA* consdata;
9998  SCIP_Real maxviol;
9999  SCIP_Bool maypropfeasible;
10000  SCIP_Longint soltag;
10001  int c;
10002 
10003  assert(scip != NULL);
10004  assert(conshdlr != NULL);
10005  assert(conss != NULL || nconss == 0);
10006  assert(result != NULL);
10007 
10008  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10009  assert(conshdlrdata != NULL);
10010 
10011  *result = SCIP_FEASIBLE;
10012  soltag = SCIPgetExprNewSoltag(scip);
10013  maxviol = 0.0;
10014  maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
10015  && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING;
10016 
10017  if( maypropfeasible && (sol == NULL || SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_LPSOL) && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
10018  maypropfeasible = FALSE;
10019 
10020  /* check nonlinear constraints for feasibility */
10021  for( c = 0; c < nconss; ++c )
10022  {
10023  assert(conss != NULL && conss[c] != NULL);
10024  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
10025 
10026  if( isConsViolated(scip, conss[c]) )
10027  {
10028  *result = SCIP_INFEASIBLE;
10029  maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
10030 
10031  consdata = SCIPconsGetData(conss[c]);
10032  assert(consdata != NULL);
10033 
10034  /* print reason for infeasibility */
10035  if( printreason )
10036  {
10037  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
10038  SCIPinfoMessage(scip, NULL, ";\n");
10039 
10040  if( consdata->lhsviol > SCIPfeastol(scip) )
10041  {
10042  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
10043  }
10044  if( consdata->rhsviol > SCIPfeastol(scip) )
10045  {
10046  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
10047  }
10048  }
10049  else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
10050  {
10051  /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
10052  return SCIP_OKAY;
10053  }
10054 
10055  /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
10056  if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
10057  maypropfeasible = FALSE;
10058 
10059  if( maypropfeasible )
10060  {
10061  if( consdata->lhsviol > SCIPfeastol(scip) )
10062  {
10063  /* check if there is a variable which may help to get the left hand side satisfied
10064  * if there is no such variable, then we cannot get feasible
10065  */
10066  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
10067  !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
10068  maypropfeasible = FALSE;
10069  }
10070  else
10071  {
10072  assert(consdata->rhsviol > SCIPfeastol(scip));
10073  /* check if there is a variable which may help to get the right hand side satisfied
10074  * if there is no such variable, then we cannot get feasible
10075  */
10076  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
10077  !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
10078  maypropfeasible = FALSE;
10079  }
10080  }
10081  }
10082  }
10083 
10084  if( *result == SCIP_INFEASIBLE && maypropfeasible )
10085  {
10086  SCIP_Bool success;
10087 
10088  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
10089 
10090  /* do not pass solution to NLP heuristic if we made it feasible this way */
10091  if( success )
10092  return SCIP_OKAY;
10093  }
10094 
10095  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
10096  {
10097  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
10098  }
10099 
10100  return SCIP_OKAY;
10101 }
10102 
10103 
10104 /** domain propagation method of constraint handler */
10105 static
10106 SCIP_DECL_CONSPROP(consPropNonlinear)
10107 { /*lint --e{715}*/
10108  int nchgbds = 0;
10109 
10110  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
10111  assert(nchgbds >= 0);
10112 
10113  /* TODO would it make sense to check for redundant constraints? */
10114 
10115  return SCIP_OKAY;
10116 }
10117 
10118 
10119 /** presolving method of constraint handler */
10120 static
10121 SCIP_DECL_CONSPRESOL(consPresolNonlinear)
10122 { /*lint --e{715}*/
10123  SCIP_CONSHDLRDATA* conshdlrdata;
10124  SCIP_Bool infeasible;
10125  int c;
10126 
10127  *result = SCIP_DIDNOTFIND;
10128 
10129  if( nconss == 0 )
10130  {
10131  *result = SCIP_DIDNOTRUN;
10132  return SCIP_OKAY;
10133  }
10134 
10135  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10136  assert(conshdlrdata != NULL);
10137 
10138  /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
10139  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
10140  if( infeasible )
10141  {
10142  *result = SCIP_CUTOFF;
10143  return SCIP_OKAY;
10144  }
10145 
10146  /* merge constraints with the same root expression */
10147  if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
10148  {
10149  SCIP_Bool success;
10150 
10151  SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
10152  if( success )
10153  *result = SCIP_SUCCESS;
10154  }
10155 
10156  /* propagate constraints */
10157  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
10158  if( *result == SCIP_CUTOFF )
10159  return SCIP_OKAY;
10160 
10161  /* propagate function domains (TODO integrate with simplify?) */
10162  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
10163  {
10164  SCIP_RESULT localresult;
10165  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
10166  if( localresult == SCIP_CUTOFF )
10167  {
10168  *result = SCIP_CUTOFF;
10169  return SCIP_OKAY;
10170  }
10171  if( localresult == SCIP_REDUCEDDOM )
10172  *result = SCIP_REDUCEDDOM;
10173  }
10174 
10175  /* check for redundant constraints, remove constraints that are a value expression */
10176  SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
10177  if( infeasible )
10178  {
10179  *result = SCIP_CUTOFF;
10180  return SCIP_OKAY;
10181  }
10182 
10183  /* try to upgrade constraints */
10184  for( c = 0; c < nconss; ++c )
10185  {
10186  SCIP_Bool upgraded;
10187 
10188  /* skip inactive and deleted constraints */
10189  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
10190  continue;
10191 
10192  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10193  }
10194 
10195  /* try to change continuous variables that appear linearly to be implicit integer */
10196  if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
10197  {
10198  SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
10199 
10200  if( infeasible )
10201  {
10202  SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
10203  *result = SCIP_CUTOFF;
10204  return SCIP_OKAY;
10205  }
10206  }
10207 
10208  /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
10209  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) && SCIPisPresolveFinished(scip)
10210  && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
10211  {
10212  /* run this presolving technique only once because we don't want to generate identical bound disjunction
10213  * constraints multiple times
10214  */
10215  conshdlrdata->checkedvarlocks = TRUE;
10216 
10217  for( c = 0; c < nconss; ++c )
10218  {
10219  int tmpnchgvartypes = 0;
10220  int tmpnaddconss = 0;
10221 
10222  SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
10223  SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
10224  SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
10225 
10226  if( infeasible )
10227  {
10228  SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
10229  *result = SCIP_CUTOFF;
10230  return SCIP_OKAY;
10231  }
10232 
10233  (*nchgvartypes) += tmpnchgvartypes;
10234  (*naddconss) += tmpnaddconss;
10235  }
10236  }
10237 
10238  if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
10239  *result = SCIP_SUCCESS;
10240  else
10241  *result = SCIP_DIDNOTFIND;
10242 
10243  return SCIP_OKAY;
10244 }
10245 
10246 
10247 /** propagation conflict resolving method of constraint handler */
10248 #ifdef SCIP_DISABLED_CODE
10249 static
10251 { /*lint --e{715}*/
10252  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10253  SCIPABORT(); /*lint --e{527}*/
10254 
10255  return SCIP_OKAY;
10256 }
10257 #else
10258 #define consRespropNonlinear NULL
10259 #endif
10260 
10261 
10262 /** variable rounding lock method of constraint handler */
10263 static
10264 SCIP_DECL_CONSLOCK(consLockNonlinear)
10265 { /*lint --e{715}*/
10266  SCIP_CONSDATA* consdata;
10267  SCIP_EXPR_OWNERDATA* ownerdata;
10268  SCIP_Bool reinitsolve = FALSE;
10269 
10270  assert(conshdlr != NULL);
10271  assert(cons != NULL);
10272 
10273  consdata = SCIPconsGetData(cons);
10274  assert(consdata != NULL);
10275  assert(consdata->expr != NULL);
10276 
10277  ownerdata = SCIPexprGetOwnerData(consdata->expr);
10278 
10279  /* check whether we need to initSolve again because
10280  * - we have enfo initialized (nenfos >= 0)
10281  * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
10282  */
10283  if( ownerdata->nenfos >= 0 )
10284  {
10285  if( (consdata->nlockspos == 0) != (nlockspos == 0) )
10286  reinitsolve = TRUE;
10287  if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
10288  reinitsolve = TRUE;
10289  }
10290 
10291  if( reinitsolve )
10292  {
10293  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10294  }
10295 
10296  /* add locks */
10297  SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
10298 
10299  if( reinitsolve )
10300  {
10301  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10302  }
10303 
10304  return SCIP_OKAY;
10305 }
10306 
10307 
10308 /** constraint activation notification method of constraint handler */
10309 static
10310 SCIP_DECL_CONSACTIVE(consActiveNonlinear)
10311 { /*lint --e{715}*/
10312  SCIP_CONSDATA* consdata;
10313  SCIP_Bool infeasible = FALSE;
10314 
10315  consdata = SCIPconsGetData(cons);
10316  assert(consdata != NULL);
10317 
10318  /* simplify root expression if the constraint has been added after presolving */
10320  {
10321  SCIP_Bool replacedroot;
10322 
10323  if( !consdata->issimplified )
10324  {
10325  SCIP_EXPR* simplified;
10326  SCIP_Bool changed;
10327 
10328  /* simplify constraint */
10329  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
10330  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
10331  assert(simplified != NULL);
10332  consdata->expr = simplified;
10333  consdata->issimplified = TRUE;
10334  }
10335 
10336  /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
10337  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
10338  assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
10339 
10340  /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
10341  {
10342  SCIP_CONSHDLRDATA* conshdlrdata;
10343  SCIP_EXPRITER* it;
10344  SCIP_EXPR* expr;
10345 
10346  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10347  assert(conshdlrdata != NULL);
10348 
10349  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
10350  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
10352  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10353  {
10354  SCIP_EXPR* child;
10355  SCIP_EXPR* hashmapexpr;
10356 
10357  child = SCIPexpriterGetChildExprDFS(it);
10358  if( !SCIPisExprVar(scip, child) )
10359  continue;
10360 
10361  /* check which expression is stored in the hashmap for the var of child */
10362  hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
10363  /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
10364  if( hashmapexpr != NULL && hashmapexpr != child )
10365  {
10366  SCIP_CALL( SCIPreplaceExprChild(scip, expr, SCIPexpriterGetChildIdxDFS(it), hashmapexpr) );
10367  }
10368  }
10369  SCIPfreeExpriter(&it);
10370  }
10371  }
10372 
10373  /* store variable expressions */
10374  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10375  {
10376  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10377  }
10378 
10379  /* add manually locks to constraints that are not checked for feasibility */
10380  if( !SCIPconsIsChecked(cons) )
10381  {
10382  assert(consdata->nlockspos == 0);
10383  assert(consdata->nlocksneg == 0);
10384 
10385  SCIP_CALL( addLocks(scip, cons, 1, 0) );
10386  }
10387 
10388  if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
10389  {
10390  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10391  }
10392 
10393  /* TODO deal with infeasibility */
10394  assert(!infeasible);
10395 
10396  return SCIP_OKAY;
10397 }
10398 
10399 
10400 /** constraint deactivation notification method of constraint handler */
10401 static
10402 SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
10403 { /*lint --e{715}*/
10404  SCIP_CONSHDLRDATA* conshdlrdata;
10405 
10406  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10407  assert(conshdlrdata != NULL);
10408 
10409  if( SCIPgetStage(scip) < SCIP_STAGE_EXITSOLVE )
10410  {
10411  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10412  }
10413 
10414  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10415  {
10416  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10417  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(cons)) );
10418  }
10419 
10420  /* remove locks that have been added in consActiveExpr() */
10421  if( !SCIPconsIsChecked(cons) )
10422  {
10423  SCIP_CALL( addLocks(scip, cons, -1, 0) );
10424 
10425  assert(SCIPconsGetData(cons)->nlockspos == 0);
10426  assert(SCIPconsGetData(cons)->nlocksneg == 0);
10427  }
10428 
10429  return SCIP_OKAY;
10430 }
10431 
10432 
10433 /** constraint enabling notification method of constraint handler */
10434 static
10435 SCIP_DECL_CONSENABLE(consEnableNonlinear)
10436 { /*lint --e{715}*/
10437  SCIP_CONSHDLRDATA* conshdlrdata;
10438 
10439  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10440  assert(conshdlrdata != NULL);
10441 
10442  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10443  {
10444  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10445  }
10446 
10447  return SCIP_OKAY;
10448 }
10449 
10450 
10451 /** constraint disabling notification method of constraint handler */
10452 static
10453 SCIP_DECL_CONSDISABLE(consDisableNonlinear)
10454 { /*lint --e{715}*/
10455  SCIP_CONSHDLRDATA* conshdlrdata;
10456 
10457  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10458  assert(conshdlrdata != NULL);
10459 
10460  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10461  {
10462  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10463  }
10464 
10465  return SCIP_OKAY;
10466 }
10467 
10468 /** variable deletion of constraint handler */
10469 #ifdef SCIP_DISABLED_CODE
10470 static
10472 { /*lint --e{715}*/
10473  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10474  SCIPABORT(); /*lint --e{527}*/
10475 
10476  return SCIP_OKAY;
10477 }
10478 #else
10479 #define consDelvarsNonlinear NULL
10480 #endif
10481 
10482 
10483 /** constraint display method of constraint handler */
10484 static
10485 SCIP_DECL_CONSPRINT(consPrintNonlinear)
10486 { /*lint --e{715}*/
10487  SCIP_CONSDATA* consdata;
10488 
10489  consdata = SCIPconsGetData(cons);
10490  assert(consdata != NULL);
10491  assert(consdata->expr != NULL);
10492 
10493  /* print left hand side for ranged constraints */
10494  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10495  {
10496  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10497  }
10498 
10499  /* print expression */
10500  SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
10501 
10502  /* print right hand side */
10503  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10504  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
10505  else if( !SCIPisInfinity(scip, consdata->rhs) )
10506  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
10507  else if( !SCIPisInfinity(scip, -consdata->lhs) )
10508  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
10509  else
10510  SCIPinfoMessage(scip, file, " [free]");
10511 
10512  return SCIP_OKAY;
10513 }
10514 
10515 
10516 /** constraint copying method of constraint handler */
10517 static
10518 SCIP_DECL_CONSCOPY(consCopyNonlinear)
10519 { /*lint --e{715}*/
10520  SCIP_CONSHDLR* targetconshdlr;
10521  SCIP_EXPR* targetexpr = NULL;
10522  SCIP_CONSDATA* sourcedata;
10523 
10524  assert(cons != NULL);
10525 
10526  sourcedata = SCIPconsGetData(sourcecons);
10527  assert(sourcedata != NULL);
10528 
10529  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10530  assert(targetconshdlr != NULL);
10531 
10532  SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
10533 
10534  if( targetexpr == NULL )
10535  *valid = FALSE;
10536 
10537  *cons = NULL;
10538  if( *valid )
10539  {
10540  /* create copy (only capture targetexpr, no need to copy again) */
10541  SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
10542  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
10543  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10544  }
10545 
10546  if( targetexpr != NULL )
10547  {
10548  /* release target expr */
10549  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
10550  }
10551 
10552  return SCIP_OKAY;
10553 }
10554 
10555 
10556 /** constraint parsing method of constraint handler */
10557 static
10558 SCIP_DECL_CONSPARSE(consParseNonlinear)
10559 { /*lint --e{715}*/
10560  SCIP_Real lhs;
10561  SCIP_Real rhs;
10562  char* endptr;
10563  SCIP_EXPR* consexprtree;
10564 
10565  SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
10566 
10567  assert(scip != NULL);
10568  assert(success != NULL);
10569  assert(str != NULL);
10570  assert(name != NULL);
10571  assert(cons != NULL);
10572 
10573  *success = FALSE;
10574 
10575  /* return if string empty */
10576  if( !*str )
10577  return SCIP_OKAY;
10578 
10579  endptr = (char*)str;
10580 
10581  /* set left and right hand side to their default values */
10582  lhs = -SCIPinfinity(scip);
10583  rhs = SCIPinfinity(scip);
10584 
10585  /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
10586 
10587  /* check for left hand side */
10588  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
10589  {
10590  /* there is a number coming, maybe it is a left-hand-side */
10591  if( !SCIPparseReal(scip, str, &lhs, &endptr) )
10592  {
10593  SCIPerrorMessage("error parsing number from <%s>\n", str);
10594  return SCIP_READERROR;
10595  }
10596 
10597  /* ignore whitespace */
10598  SCIP_CALL( SCIPskipSpace(&endptr) );
10599 
10600  if( endptr[0] != '<' || endptr[1] != '=' )
10601  {
10602  /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
10603  lhs = -SCIPinfinity(scip);
10604  }
10605  else
10606  {
10607  /* it was indeed a left-hand-side, so continue parsing after it */
10608  str = endptr + 2;
10609 
10610  /* ignore whitespace */
10611  SCIP_CALL( SCIPskipSpace((char**)&str) );
10612  }
10613  }
10614 
10615  SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
10616 
10617  /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
10618  SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
10619 
10620  /* check for left or right hand side */
10621  SCIP_CALL( SCIPskipSpace((char**)&str) );
10622 
10623  /* check for free constraint */
10624  if( strncmp(str, "[free]", 6) == 0 )
10625  {
10626  if( !SCIPisInfinity(scip, -lhs) )
10627  {
10628  SCIPerrorMessage("cannot have left hand side and [free] status \n");
10629  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10630  return SCIP_OKAY;
10631  }
10632  *success = TRUE;
10633  }
10634  else
10635  {
10636  switch( *str )
10637  {
10638  case '<':
10639  *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
10640  break;
10641  case '=':
10642  if( !SCIPisInfinity(scip, -lhs) )
10643  {
10644  SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
10645  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10646  return SCIP_OKAY;
10647  }
10648  else
10649  {
10650  *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
10651  lhs = rhs;
10652  }
10653  break;
10654  case '>':
10655  if( !SCIPisInfinity(scip, -lhs) )
10656  {
10657  SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
10658  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10659  return SCIP_OKAY;
10660  }
10661  else
10662  {
10663  *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
10664  break;
10665  }
10666  case '\0':
10667  *success = TRUE;
10668  break;
10669  default:
10670  SCIPerrorMessage("unexpected character %c\n", *str);
10671  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10672  return SCIP_OKAY;
10673  }
10674  }
10675 
10676  /* create constraint */
10677  SCIP_CALL( createCons(scip, conshdlr, cons, name,
10678  consexprtree, lhs, rhs, FALSE,
10679  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10680  assert(*cons != NULL);
10681 
10682  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10683 
10684  SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
10685 
10686  return SCIP_OKAY;
10687 }
10688 
10689 
10690 /** constraint method of constraint handler which returns the variables (if possible) */
10691 static
10692 SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
10693 { /*lint --e{715}*/
10694  SCIP_CONSDATA* consdata;
10695  int i;
10696 
10697  consdata = SCIPconsGetData(cons);
10698  assert(consdata != NULL);
10699 
10700  /* store variable expressions if not done so far */
10701  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10702 
10703  /* check whether array is too small in order to store all variables */
10704  if( varssize < consdata->nvarexprs )
10705  {
10706  *success = FALSE;
10707  return SCIP_OKAY;
10708  }
10709 
10710  for( i = 0; i < consdata->nvarexprs; ++i )
10711  {
10712  vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
10713  assert(vars[i] != NULL);
10714  }
10715 
10716  *success = TRUE;
10717 
10718  return SCIP_OKAY;
10719 }
10720 
10721 /** constraint method of constraint handler which returns the number of variables (if possible) */
10722 static
10723 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
10724 { /*lint --e{715}*/
10725  SCIP_CONSDATA* consdata;
10726 
10727  consdata = SCIPconsGetData(cons);
10728  assert(consdata != NULL);
10729 
10730  /* store variable expressions if not done so far */
10731  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10732 
10733  *nvars = consdata->nvarexprs;
10734  *success = TRUE;
10735 
10736  return SCIP_OKAY;
10737 }
10738 
10739 /** constraint handler method to suggest dive bound changes during the generic diving algorithm */
10740 #ifdef SCIP_DISABLED_CODE
10741 static
10743 { /*lint --e{715}*/
10744  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10745  SCIPABORT(); /*lint --e{527}*/
10746 
10747  return SCIP_OKAY;
10748 }
10749 #else
10750 #define consGetDiveBdChgsNonlinear NULL
10751 #endif
10752 
10753 /** output method of statistics table to output file stream 'file' */
10754 static
10755 SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
10756 { /*lint --e{715}*/
10757  SCIP_CONSHDLR* conshdlr;
10758  SCIP_CONSHDLRDATA* conshdlrdata;
10759 
10760  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10761  assert(conshdlr != NULL);
10762 
10763  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10764  assert(conshdlrdata != NULL);
10765 
10766  /* print statistics for constraint handler */
10767  SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
10768  SCIPinfoMessage(scip, file, " enforce%-10s:", "");
10769  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
10770  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
10771  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
10772  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
10773  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
10774  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
10775  SCIPinfoMessage(scip, file, "\n");
10776  SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
10777  SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
10778  SCIPinfoMessage(scip, file, "\n");
10779 
10780  return SCIP_OKAY;
10781 }
10782 
10783 /** output method of statistics table to output file stream 'file' */
10784 static
10785 SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
10786 { /*lint --e{715}*/
10787  SCIP_CONSHDLR* conshdlr;
10788  SCIP_CONSHDLRDATA* conshdlrdata;
10789 
10790  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10791  assert(conshdlr != NULL);
10792 
10793  /* skip nlhdlr table if there never were active nonlinear constraints */
10794  if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
10795  return SCIP_OKAY;
10796 
10797  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10798  assert(conshdlrdata != NULL);
10799 
10800  /* print statistics for nonlinear handlers */
10801  SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
10802 
10803  return SCIP_OKAY;
10804 }
10805 
10806 /** execution method of display nlhdlrs dialog */
10807 static
10808 SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
10809 { /*lint --e{715}*/
10810  SCIP_CONSHDLR* conshdlr;
10811  SCIP_CONSHDLRDATA* conshdlrdata;
10812  int i;
10813 
10814  /* add dialog to history of dialogs that have been executed */
10815  SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
10816 
10817  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10818  assert(conshdlr != NULL);
10819 
10820  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10821  assert(conshdlrdata != NULL);
10822 
10823  /* display list of nonlinear handler */
10824  SCIPdialogMessage(scip, NULL, "\n");
10825  SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
10826  SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
10827  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10828  {
10829  SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
10830  assert(nlhdlr != NULL);
10831 
10832  SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
10833  SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
10834  SCIPdialogMessage(scip, NULL, " %10d ", SCIPnlhdlrGetDetectPriority(nlhdlr));
10835  SCIPdialogMessage(scip, NULL, " %11d ", SCIPnlhdlrGetEnfoPriority(nlhdlr));
10836  SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
10837  SCIPdialogMessage(scip, NULL, "\n");
10838  }
10839  SCIPdialogMessage(scip, NULL, "\n");
10840 
10841  /* next dialog will be root dialog again */
10842  *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
10843 
10844  return SCIP_OKAY;
10845 }
10846 
10847 /*
10848  * constraint handler specific interface methods
10849  */
10850 
10851 /** creates the handler for nonlinear constraints and includes it in SCIP */
10853  SCIP* scip /**< SCIP data structure */
10854  )
10855 {
10856  SCIP_CONSHDLRDATA* conshdlrdata;
10857  SCIP_DIALOG* parentdialog;
10858 
10859  /* create nonlinear constraint handler data */
10860  SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
10861  conshdlrdata->intevalvar = intEvalVarBoundTightening;
10862  conshdlrdata->curboundstag = 1;
10863  conshdlrdata->lastboundrelax = 1;
10864  conshdlrdata->curpropboundstag = 1;
10865  conshdlrdata->newsoleventfilterpos = -1;
10866  SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
10867  SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
10868  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
10869 
10870  /* include constraint handler */
10876  conshdlrCopyNonlinear,
10877  consFreeNonlinear, consInitNonlinear, consExitNonlinear,
10878  consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
10879  consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
10880  consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
10881  consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
10882  consActiveNonlinear, consDeactiveNonlinear,
10883  consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
10884  consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
10885  consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, conshdlrdata) );
10886 
10887  /* add nonlinear constraint handler parameters */
10888  /* TODO organize into more subcategories */
10889  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
10890  "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
10891  &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
10892 
10893  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
10894  "whether to check bounds of all auxiliary variable to seed reverse propagation",
10895  &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
10896 
10897  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
10898  "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",
10899  &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
10900 
10901  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
10902  "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
10903  &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10904 
10905  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
10906  "by how much to relax constraint sides during bound tightening",
10907  &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10908 
10909  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
10910  "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
10911  &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
10912 
10913  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
10914  "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
10915  &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
10916 
10917  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
10918  "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
10919  &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
10920 
10921  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
10922  "maximal number of auxiliary expressions per bilinear term",
10923  &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
10924 
10925  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
10926  "whether to reformulate products of binary variables during presolving",
10927  &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
10928 
10929  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
10930  "whether to use the AND constraint handler for reformulating binary products",
10931  &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
10932 
10933  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
10934  "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
10935  &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
10936 
10937  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
10938  "whether to forbid multiaggregation of nonlinear variables",
10939  &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
10940 
10941  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
10942  "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
10943  &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
10944 
10945  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
10946  "whether to (re)run propagation in enforcement",
10947  &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
10948 
10949  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
10950  "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
10951  &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
10952 
10953  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
10954  "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
10955  &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
10956 
10957  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
10958  "consider efficacy requirement when deciding whether a cut is \"strong\"",
10959  &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
10960 
10961  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
10962  "whether to force \"strong\" cuts in enforcement",
10963  &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
10964 
10965  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
10966  "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
10967  &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
10968 
10969  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
10970  "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
10971  &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
10972 
10973  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
10974  "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",
10975  &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
10976 
10977  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
10978  "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
10979  &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
10980 
10981  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
10982  "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)",
10983  &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
10984 
10985  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
10986  "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
10987  &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
10988 
10989  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
10990  "whether to use external branching candidates and branching rules for branching",
10991  &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
10992 
10993  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
10994  "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
10995  &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
10996 
10997  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
10998  "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
10999  &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
11000 
11001  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
11002  "weight by how much to consider the violation assigned to a variable for its branching score",
11003  &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11004 
11005  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
11006  "weight by how much to consider the dual values of rows that contain a variable for its branching score",
11007  &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11008 
11009  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
11010  "weight by how much to consider the pseudo cost of a variable for its branching score",
11011  &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11012 
11013  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
11014  "weight by how much to consider the domain width in branching score",
11015  &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11016 
11017  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
11018  "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
11019  &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
11020 
11021  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
11022  "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
11023  &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
11024 
11025  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
11026  "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
11027  &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
11028 
11029  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
11030  "minimum pseudo-cost update count required to consider pseudo-costs reliable",
11031  &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11032 
11033  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
11034  "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)",
11035  &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
11036 
11037  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
11038  "whether to assume that any constraint is convex",
11039  &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
11040 
11041  /* include handler for bound change events */
11042  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
11043  "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
11044  assert(conshdlrdata->eventhdlr != NULL);
11045 
11046  /* include tables for statistics */
11047  assert(SCIPfindTable(scip, TABLE_NAME_NONLINEAR) == NULL);
11049  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
11051 
11052  assert(SCIPfindTable(scip, TABLE_NAME_NLHDLR) == NULL);
11054  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
11056 
11057  /* create, include, and release display nlhdlrs dialog */
11058  if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
11059  {
11060  SCIP_DIALOG* dialog;
11061 
11062  assert(parentdialog != NULL);
11063  assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
11064 
11065  SCIP_CALL( SCIPincludeDialog(scip, &dialog,
11066  NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
11068  SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
11069  SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
11070  }
11071 
11072  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
11073  processNewSolutionEvent, NULL) );
11074 
11075  return SCIP_OKAY;
11076 }
11077 
11078 /** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
11080  SCIP* scip, /**< SCIP data structure */
11081  SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
11082  int priority, /**< priority of upgrading method */
11083  SCIP_Bool active, /**< should the upgrading method by active by default? */
11084  const char* conshdlrname /**< name of the constraint handler */
11085  )
11086 {
11087  SCIP_CONSHDLR* conshdlr;
11088  SCIP_CONSHDLRDATA* conshdlrdata;
11089  CONSUPGRADE* consupgrade;
11090  char paramname[SCIP_MAXSTRLEN];
11091  char paramdesc[SCIP_MAXSTRLEN];
11092  int i;
11093 
11094  assert(conshdlrname != NULL );
11095  assert(nlconsupgd != NULL);
11096 
11097  /* find the nonlinear constraint handler */
11098  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11099  if( conshdlr == NULL )
11100  {
11101  SCIPerrorMessage("nonlinear constraint handler not found\n");
11102  return SCIP_PLUGINNOTFOUND;
11103  }
11104 
11105  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11106  assert(conshdlrdata != NULL);
11107 
11108  /* check whether upgrade method exists already */
11109  for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
11110  {
11111  if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
11112  {
11113 #ifdef SCIP_DEBUG
11114  SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
11115 #endif
11116  return SCIP_OKAY;
11117  }
11118  }
11119 
11120  /* create a nonlinear constraint upgrade data object */
11121  SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
11122  consupgrade->consupgd = nlconsupgd;
11123  consupgrade->priority = priority;
11124  consupgrade->active = active;
11125 
11126  /* insert nonlinear constraint upgrade method into constraint handler data */
11127  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
11128  assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
11129 
11130  for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
11131  conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
11132  assert(0 <= i && i <= conshdlrdata->nconsupgrades);
11133  conshdlrdata->consupgrades[i] = consupgrade;
11134  conshdlrdata->nconsupgrades++;
11135 
11136  /* adds parameter to turn on and off the upgrading step */
11137  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
11138  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
11140  paramname, paramdesc,
11141  &consupgrade->active, FALSE, active, NULL, NULL) );
11142 
11143  return SCIP_OKAY;
11144 }
11145 
11146 /** creates and captures a nonlinear constraint
11147  *
11148  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11149  */
11151  SCIP* scip, /**< SCIP data structure */
11152  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11153  const char* name, /**< name of constraint */
11154  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11155  SCIP_Real lhs, /**< left hand side of constraint */
11156  SCIP_Real rhs, /**< right hand side of constraint */
11157  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11158  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11159  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11160  * Usually set to TRUE. */
11161  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11162  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11163  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11164  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11165  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11166  * Usually set to TRUE. */
11167  SCIP_Bool local, /**< is constraint only valid locally?
11168  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11169  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11170  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11171  * adds coefficients to this constraint. */
11172  SCIP_Bool dynamic, /**< is constraint subject to aging?
11173  * Usually set to FALSE. Set to TRUE for own cuts which
11174  * are separated as constraints. */
11175  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11176  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11177  )
11178 {
11179  /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
11180  SCIP_CONSHDLR* conshdlr;
11181 
11182  /* find the nonlinear constraint handler */
11183  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11184  if( conshdlr == NULL )
11185  {
11186  SCIPerrorMessage("nonlinear constraint handler not found\n");
11187  return SCIP_PLUGINNOTFOUND;
11188  }
11189 
11190  /* create constraint */
11191  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
11192  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11193 
11194  return SCIP_OKAY;
11195 }
11196 
11197 /** creates and captures a nonlinear constraint with all its constraint flags set to their default values
11198  *
11199  * All flags can be set via SCIPconsSetFLAGNAME-methods.
11200  *
11201  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
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  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11210  SCIP_Real lhs, /**< left hand side of constraint */
11211  SCIP_Real rhs /**< right hand side of constraint */
11212  )
11213 {
11214  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
11215  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11216 
11217  return SCIP_OKAY;
11218 }
11219 
11220 /** creates and captures a quadratic nonlinear constraint
11221  *
11222  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11223  */
11225  SCIP* scip, /**< SCIP data structure */
11226  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11227  const char* name, /**< name of constraint */
11228  int nlinvars, /**< number of linear terms */
11229  SCIP_VAR** linvars, /**< array with variables in linear part */
11230  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11231  int nquadterms, /**< number of quadratic terms */
11232  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11233  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11234  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11235  SCIP_Real lhs, /**< left hand side of quadratic equation */
11236  SCIP_Real rhs, /**< right hand side of quadratic equation */
11237  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11238  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11239  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11240  * Usually set to TRUE. */
11241  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11242  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11243  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11244  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11245  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11246  * Usually set to TRUE. */
11247  SCIP_Bool local, /**< is constraint only valid locally?
11248  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11249  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11250  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11251  * adds coefficients to this constraint. */
11252  SCIP_Bool dynamic, /**< is constraint subject to aging?
11253  * Usually set to FALSE. Set to TRUE for own cuts which
11254  * are separated as constraints. */
11255  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11256  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11257  )
11258 {
11259  SCIP_CONSHDLR* conshdlr;
11260  SCIP_EXPR* expr;
11261 
11262  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
11263  assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
11264 
11265  /* get nonlinear constraint handler */
11266  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11267  if( conshdlr == NULL )
11268  {
11269  SCIPerrorMessage("nonlinear constraint handler not found\n");
11270  return SCIP_PLUGINNOTFOUND;
11271  }
11272 
11273  /* create quadratic expression */
11274  SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
11275  assert(expr != NULL);
11276 
11277  /* create nonlinear constraint */
11278  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
11279  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11280 
11281  /* release quadratic expression (captured by constraint now) */
11282  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11283 
11284  return SCIP_OKAY;
11285 }
11286 
11287 /** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
11288  *
11289  * All flags can be set via SCIPconsSetFLAGNAME-methods.
11290  *
11291  * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
11292  *
11293  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11294  */
11296  SCIP* scip, /**< SCIP data structure */
11297  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11298  const char* name, /**< name of constraint */
11299  int nlinvars, /**< number of linear terms */
11300  SCIP_VAR** linvars, /**< array with variables in linear part */
11301  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11302  int nquadterms, /**< number of quadratic terms */
11303  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11304  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11305  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11306  SCIP_Real lhs, /**< left hand side of quadratic equation */
11307  SCIP_Real rhs /**< right hand side of quadratic equation */
11308  )
11309 {
11310  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11311  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11312 
11313  return SCIP_OKAY;
11314 }
11315 
11316 /** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
11317  *
11318  * \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$
11319  *
11320  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11321  */
11323  SCIP* scip, /**< SCIP data structure */
11324  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11325  const char* name, /**< name of constraint */
11326  int nvars, /**< number of variables on left hand side of constraint (n) */
11327  SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
11328  SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
11329  SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
11330  SCIP_Real constant, /**< constant on left hand side (gamma) */
11331  SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
11332  SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
11333  SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
11334  )
11335 {
11336  SCIP_EXPR* expr;
11337  SCIP_EXPR* lhssum;
11338  SCIP_EXPR* terms[2];
11339  SCIP_Real termcoefs[2];
11340  int i;
11341 
11342  assert(vars != NULL || nvars == 0);
11343 
11344  SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
11345  for( i = 0; i < nvars; ++i )
11346  {
11347  SCIP_EXPR* varexpr;
11348  SCIP_EXPR* powexpr;
11349 
11350  SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
11351  if( offsets != NULL && offsets[i] != 0.0 )
11352  {
11353  SCIP_EXPR* sum;
11354  SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
11355  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
11356  SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
11357  }
11358  else
11359  {
11360  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
11361  }
11362 
11363  SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
11364  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
11365  SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
11366  }
11367 
11368  SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
11369  SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
11370  termcoefs[0] = 1.0;
11371 
11372  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
11373  termcoefs[1] = -rhscoeff;
11374 
11375  SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
11376 
11377  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11378  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11379 
11380  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
11381 
11382  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11383 
11384  return SCIP_OKAY;
11385 }
11386 
11387 /** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
11388  *
11389  * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
11390  *
11391  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11392  */
11394  SCIP* scip, /**< SCIP data structure */
11395  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11396  const char* name, /**< name of constraint */
11397  SCIP_VAR* x, /**< nonlinear variable x in constraint */
11398  SCIP_VAR* z, /**< linear variable z in constraint */
11399  SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
11400  SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
11401  SCIP_Real zcoef, /**< coefficient of z in constraint */
11402  SCIP_Real lhs, /**< left hand side of constraint */
11403  SCIP_Real rhs /**< right hand side of constraint */
11404  )
11405 {
11406  SCIP_EXPR* xexpr;
11407  SCIP_EXPR* terms[2];
11408  SCIP_Real coefs[2];
11409  SCIP_EXPR* sumexpr;
11410 
11411  assert(x != NULL);
11412  assert(z != NULL);
11413 
11414  SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
11415  if( xoffset != 0.0 )
11416  {
11417  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
11418  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
11419 
11420  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11421  }
11422  else
11423  {
11424  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
11425  }
11426  coefs[0] = 1.0;
11427 
11428  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
11429  coefs[1] = zcoef;
11430 
11431  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
11432 
11433  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
11434 
11435  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11436  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11437  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11438  SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
11439 
11440  return SCIP_OKAY;
11441 }
11442 
11443 /** gets tag indicating current local variable bounds */
11445  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11446  )
11447 {
11448  SCIP_CONSHDLRDATA* conshdlrdata;
11449 
11450  assert(conshdlr != NULL);
11451  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11452 
11453  return conshdlrdata->curboundstag;
11454 }
11455 
11456 /** gets the `curboundstag` from the last time where variable bounds were relaxed */
11458  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11459  )
11460 {
11461  SCIP_CONSHDLRDATA* conshdlrdata;
11462 
11463  assert(conshdlr != NULL);
11464  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11465 
11466  return conshdlrdata->lastboundrelax;
11467 }
11468 
11469 /** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
11470  *
11471  * @attention This method is not intended for normal use.
11472  * These tags are maintained by the event handler for variable bound change events.
11473  * This method is used by some unittests.
11474  */
11476  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11477  SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
11478  )
11479 {
11480  SCIP_CONSHDLRDATA* conshdlrdata;
11481 
11482  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11483  assert(conshdlrdata != NULL);
11484 
11485  ++conshdlrdata->curboundstag;
11486  assert(conshdlrdata->curboundstag > 0);
11487 
11488  if( boundrelax )
11489  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
11490 }
11491 
11492 /** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
11494  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11495  )
11496 {
11497  assert(conshdlr != NULL);
11498 
11499  return SCIPconshdlrGetData(conshdlr)->var2expr;
11500 }
11501 
11502 /** processes a rowprep for cut addition and maybe report branchscores */
11504  SCIP* scip, /**< SCIP data structure */
11505  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
11506  SCIP_CONS* cons, /**< nonlinear constraint */
11507  SCIP_EXPR* expr, /**< expression */
11508  SCIP_ROWPREP* rowprep, /**< cut to be added */
11509  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
11510  SCIP_VAR* auxvar, /**< auxiliary variable */
11511  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
11512  SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
11513  SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
11514  SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
11515  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
11516  SCIP_RESULT* result /**< pointer to store the result */
11517  )
11518 {
11519  SCIP_Real cutviol;
11520  SCIP_CONSHDLRDATA* conshdlrdata;
11521  SCIP_Real auxvarvalue = SCIP_INVALID;
11522  SCIP_Bool sepasuccess;
11523  SCIP_Real estimateval = SCIP_INVALID;
11524  SCIP_Real mincutviolation;
11525 
11526  assert(nlhdlr != NULL);
11527  assert(cons != NULL);
11528  assert(expr != NULL);
11529  assert(rowprep != NULL);
11530  assert(auxvar != NULL);
11531  assert(result != NULL);
11532 
11533  /* decide on minimal violation of cut */
11534  if( sol == NULL )
11535  mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
11536  else
11537  mincutviolation = SCIPfeastol(scip);
11538 
11539  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11540  assert(conshdlrdata != NULL);
11541 
11542  sepasuccess = TRUE;
11543 
11544  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
11545  if( cutviol > 0.0 )
11546  {
11547  auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
11548 
11549  /* check whether cut is weak (if f(x) not defined, then it's never weak) */
11550  if( !allowweakcuts && auxvalue != SCIP_INVALID )
11551  {
11552  /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
11553  * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
11554  * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
11555  * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
11556  * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
11557  * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
11558  *
11559  * if we are overestimating, we have z >= c'x-b >= f(x)
11560  * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
11561  * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
11562  * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
11563  *
11564  * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
11565  */
11566  if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11567  ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11568  {
11569  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
11570  "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11571  SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11572  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
11573  sepasuccess = FALSE;
11574  }
11575  }
11576 
11577  /* save estimator value for later, see long comment above why this gives the value for c'x-b */
11578  estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
11579  }
11580  else
11581  {
11582  sepasuccess = FALSE;
11583  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
11584  "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
11585  }
11586 
11587  /* clean up estimator */
11588  if( sepasuccess )
11589  {
11590  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
11591  "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11592  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
11593  SCIPprintRowprep(scip, rowprep, enfologfile); )
11594 
11595  /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
11596  * instead, may even scale them down, that is, scale so that max coef is close to 1
11597  */
11598  if( !allowweakcuts )
11599  {
11600  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
11601 
11602  if( !sepasuccess )
11603  {
11604  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
11605  }
11606  else
11607  {
11608  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
11609  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
11610  "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
11611  if( sepasuccess )
11612  sepasuccess = cutviol > mincutviolation;
11613  }
11614 
11615  if( sepasuccess && auxvalue != SCIP_INVALID )
11616  {
11617  /* check whether cut is weak now
11618  * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
11619  * reconstructing estimateval from cutviol (TODO improve or remove?)
11620  */
11621  SCIP_Real auxvarcoef = 0.0;
11622  int i;
11623 
11624  /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
11625  * it should be...
11626  */
11627  for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
11628  {
11629  if( SCIProwprepGetVars(rowprep)[i] == auxvar )
11630  {
11631  auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
11632  break;
11633  }
11634  }
11635 
11636  if( auxvarcoef == 0.0 ||
11637  (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11638  ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11639  {
11640  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11641  auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
11642  sepasuccess = FALSE;
11643  }
11644  }
11645  }
11646  else
11647  {
11648  /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
11649 
11650  /* if estimate didn't report branchscores explicitly, then consider branching on those children for
11651  * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
11652  */
11653  if( !branchscoresuccess )
11655 
11656  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
11657 
11658  if( !sepasuccess )
11659  {
11660  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
11661  SCIProwprepGetNModifiedVars(rowprep), cutviol); )
11662  }
11663 
11664  /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
11665  * changed
11666  */
11667  if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
11668  {
11669  SCIP_Real violscore;
11670 
11671 #ifdef BRSCORE_ABSVIOL
11672  violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
11673 #else
11674  SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
11675 #endif
11676  SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
11677 
11678  /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
11679  * - were fixed,
11680  * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
11681  * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
11682  * the first case came up again in #3085 and I don't see how to exclude this in the assert,
11683  * so I'm disabling the assert for now
11684  */
11685  /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
11686  strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
11687  }
11688  }
11689  }
11690 
11691  /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
11692  if( sepasuccess )
11693  {
11694  SCIP_ROW* row;
11695 
11696  if( conshdlrdata->branchdualweight > 0.0 )
11697  {
11698  /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
11699  * skip if gap is zero
11700  */
11701  if( auxvalue == SCIP_INVALID )
11702  strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
11703  else if( !SCIPisEQ(scip, auxvalue, estimateval) )
11704  {
11705  char gap[40];
11706  (void) SCIPsnprintf(gap, 40, "_estimategap=%g", REALABS(auxvalue - estimateval));
11707  strcat(SCIProwprepGetName(rowprep), gap);
11708  }
11709  }
11710 
11711  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
11712 
11713  if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
11714  {
11715  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
11716  SCIPgetCutEfficacy(scip, sol, row), SCIPgetSepaMinEfficacy(scip)); )
11717  }
11718  else if( !SCIPisCutApplicable(scip, row) )
11719  {
11720  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
11721  }
11722  else
11723  {
11724  SCIP_Bool infeasible;
11725 
11726  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
11727  SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
11728 
11729  /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
11730  * if we haven't found strong cuts before)
11731  */
11732  SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
11733 
11734  /* mark row as not removable from LP for current node (this can prevent some cycling) */
11735  if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
11736  SCIPmarkRowNotRemovableLocal(scip, row);
11737 
11738  if( infeasible )
11739  {
11740  *result = SCIP_CUTOFF;
11742  }
11743  else
11744  {
11745  *result = SCIP_SEPARATED;
11747  }
11748  }
11749 
11750  SCIP_CALL( SCIPreleaseRow(scip, &row) );
11751  }
11752  else if( branchscoresuccess )
11753  {
11754  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
11755  "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
11756 
11757  /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
11758  * expressions eligible for branching candidate, see enforceConstraints() and branching()
11759  */
11760  *result = SCIP_BRANCHED;
11761  }
11762  else
11763  {
11764  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
11765  "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
11766  " (!)" : ""); )
11767  }
11768 
11769  return SCIP_OKAY;
11770 }
11771 
11772 /** returns whether all nonlinear constraints are assumed to be convex */
11774  SCIP_CONSHDLR* conshdlr
11775  )
11776 {
11777  SCIP_CONSHDLRDATA* conshdlrdata;
11778 
11779  assert(conshdlr != NULL);
11780 
11781  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11782  assert(conshdlrdata != NULL);
11783 
11784  return conshdlrdata->assumeconvex;
11785 }
11786 
11787 /** collects all bilinear terms for a given set of constraints
11788  *
11789  * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
11790  * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
11791  */
11793  SCIP* scip, /**< SCIP data structure */
11794  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11795  SCIP_CONS** conss, /**< nonlinear constraints */
11796  int nconss /**< total number of nonlinear constraints */
11797  )
11798 {
11799  assert(conshdlr != NULL);
11800  assert(conss != NULL || nconss == 0);
11801 
11802  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11803 
11804  return SCIP_OKAY;
11805 }
11806 
11807 /** returns the total number of bilinear terms that are contained in all nonlinear constraints
11808  *
11809  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11810  */
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->nbilinterms;
11823 }
11824 
11825 /** returns all bilinear terms that are contained in all nonlinear constraints
11826  *
11827  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11828  * @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.
11829  */
11831  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11832  )
11833 {
11834  SCIP_CONSHDLRDATA* conshdlrdata;
11835 
11836  assert(conshdlr != NULL);
11837 
11838  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11839  assert(conshdlrdata != NULL);
11840 
11841  return conshdlrdata->bilinterms;
11842 }
11843 
11844 /** returns the index of the bilinear term representing the product of the two given variables
11845  *
11846  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11847  * @return The method returns -1 if the variables do not appear bilinearly.
11848  */
11850  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11851  SCIP_VAR* x, /**< first variable */
11852  SCIP_VAR* y /**< second variable */
11853  )
11854 {
11855  SCIP_CONSHDLRDATA* conshdlrdata;
11857  int idx;
11858 
11859  assert(conshdlr != NULL);
11860  assert(x != NULL);
11861  assert(y != NULL);
11862 
11863  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11864  assert(conshdlrdata != NULL);
11865 
11866  if( conshdlrdata->bilinhashtable == NULL )
11867  {
11868  return -1;
11869  }
11870 
11871  /* ensure that x.index <= y.index */
11872  if( SCIPvarCompare(x, y) == 1 )
11873  {
11874  SCIPswapPointers((void**)&x, (void**)&y);
11875  }
11876  assert(SCIPvarCompare(x, y) < 1);
11877 
11878  /* use a new entry to find the image in the bilinear hash table */
11879  entry.x = x;
11880  entry.y = y;
11881  idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
11882  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11883  assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
11884  assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
11885 
11886  return idx;
11887 }
11888 
11889 /** returns the bilinear term that represents the product of two given variables
11890  *
11891  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11892  * @return The method returns NULL if the variables do not appear bilinearly.
11893  */
11895  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11896  SCIP_VAR* x, /**< first variable */
11897  SCIP_VAR* y /**< second variable */
11898  )
11899 {
11900  SCIP_CONSHDLRDATA* conshdlrdata;
11901  int idx;
11902 
11903  assert(conshdlr != NULL);
11904  assert(x != NULL);
11905  assert(y != NULL);
11906 
11907  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11908  assert(conshdlrdata != NULL);
11909 
11910  idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
11911  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11912 
11913  if( idx >= 0 )
11914  {
11915  return &conshdlrdata->bilinterms[idx];
11916  }
11917 
11918  return NULL;
11919 }
11920 
11921 /** evaluates an auxiliary expression for a bilinear term */
11923  SCIP* scip, /**< SCIP data structure */
11924  SCIP_VAR* x, /**< first variable of the bilinear term */
11925  SCIP_VAR* y, /**< second variable of the bilinear term */
11926  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
11927  SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
11928  )
11929 {
11930  assert(scip != NULL);
11931  assert(x != NULL);
11932  assert(y != NULL);
11933  assert(auxexpr != NULL);
11934  assert(auxexpr->auxvar != NULL);
11935 
11936  return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
11937  auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
11938 }
11939 
11940 /** stores the variables of a bilinear term in the data of the constraint handler */
11942  SCIP* scip, /**< SCIP data structure */
11943  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11944  SCIP_VAR* x, /**< first variable */
11945  SCIP_VAR* y, /**< second variable */
11946  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11947  int nlockspos, /**< number of positive expression locks */
11948  int nlocksneg /**< number of negative expression locks */
11949  )
11950 {
11951  SCIP_CONSHDLRDATA* conshdlrdata;
11953  int idx;
11954 
11955  assert(conshdlr != NULL);
11956 
11957  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11958  assert(conshdlrdata != NULL);
11959 
11960  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
11961 
11962  term = &conshdlrdata->bilinterms[idx];
11963  assert(term != NULL);
11964  assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
11965  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) */
11966 
11967  /* store and capture auxiliary variable */
11968  if( auxvar != NULL )
11969  {
11970  term->aux.var = auxvar;
11971  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
11972  }
11973 
11974  return SCIP_OKAY;
11975 }
11976 
11977 /** stores the variables of a bilinear term in the data of the constraint handler */
11979  SCIP* scip, /**< SCIP data structure */
11980  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11981  SCIP_VAR* x, /**< first variable */
11982  SCIP_VAR* y, /**< second variable */
11983  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11984  SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
11985  SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
11986  SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
11987  SCIP_Real cst, /**< constant of the auxiliary expression */
11988  SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
11989  )
11990 {
11991  SCIP_CONSHDLRDATA* conshdlrdata;
11993  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr;
11994  int idx;
11995  int nlockspos;
11996  int nlocksneg;
11997  SCIP_Bool added;
11998 
11999  assert(conshdlr != NULL);
12000 
12001  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12002  assert(conshdlrdata != NULL);
12003 
12004  nlockspos = overestimate ? 1 : 0;
12005  nlocksneg = overestimate ? 0 : 1;
12006 
12007  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
12008 
12009  term = &conshdlrdata->bilinterms[idx];
12010  assert(term != NULL);
12011  assert(SCIPvarCompare(term->x, term->y) < 1);
12012 
12013  if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
12014  {
12015  SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
12016  /* this is the case where we are adding an implicitly defined relation for a product that has already
12017  * been explicitly defined; convert auxvar into an auxexpr */
12018 
12019  /* nothing to do if we aren't allowed to add more than one auxexpr per term */
12020  if( conshdlrdata->bilinmaxnauxexprs <= 1 )
12021  return SCIP_OKAY;
12022 
12023  SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
12024  auxvarexpr->cst = 0.0;
12025  auxvarexpr->coefs[0] = 1.0;
12026  auxvarexpr->coefs[1] = 0.0;
12027  auxvarexpr->coefs[2] = 0.0;
12028  auxvarexpr->auxvar = term->aux.var;
12029  auxvarexpr->underestimate = term->nlocksneg > 0;
12030  auxvarexpr->overestimate = term->nlockspos > 0;
12031 
12032  /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
12033  term->aux.exprs = NULL;
12034 
12035  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
12036 
12037  /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
12038  assert(added);
12039  }
12040 
12041  /* create and add auxexpr */
12042  SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
12043  auxexpr->underestimate = !overestimate;
12044  auxexpr->overestimate = overestimate;
12045  auxexpr->auxvar = auxvar;
12046  auxexpr->coefs[0] = coefaux;
12047  if( term->x == x )
12048  {
12049  assert(term->y == y);
12050  auxexpr->coefs[1] = coefx;
12051  auxexpr->coefs[2] = coefy;
12052  }
12053  else
12054  {
12055  assert(term->x == y);
12056  assert(term->y == x);
12057  auxexpr->coefs[1] = coefy;
12058  auxexpr->coefs[2] = coefx;
12059  }
12060  auxexpr->cst = cst;
12061  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
12062 
12063  if( !added )
12064  {
12065  SCIPfreeBlockMemory(scip, &auxexpr);
12066  }
12067  else if( auxvar != NULL )
12068  { /* capture auxiliary variable */
12069  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
12070  }
12071 
12072  return SCIP_OKAY;
12073 }
12074 
12075 /* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
12077  SCIP* scip, /**< SCIP data structure */
12078  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12079  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
12080  SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
12081  void* fundata, /**< data for function evaluation (can be NULL) */
12082  SCIP_Real* xstar, /**< point to be separated */
12083  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
12084  int nallvars, /**< half of the length of box */
12085  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
12086  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
12087  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
12088  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
12089  )
12090 {
12091  SCIP_Real* corner;
12092  SCIP_Real* funvals;
12093  int* nonfixedpos;
12094  SCIP_Real maxfaceterror;
12095  int nvars; /* number of nonfixed variables */
12096  unsigned int ncorners;
12097  unsigned int i;
12098  int j;
12099 
12100  assert(scip != NULL);
12101  assert(conshdlr != NULL);
12102  assert(function != NULL);
12103  assert(xstar != NULL);
12104  assert(box != NULL);
12105  assert(success != NULL);
12106  assert(facetcoefs != NULL);
12107  assert(facetconstant != NULL);
12108 
12109  *success = FALSE;
12110 
12111  /* identify fixed variables */
12112  SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
12113  nvars = 0;
12114  for( j = 0; j < nallvars; ++j )
12115  {
12116  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12117  continue;
12118  nonfixedpos[nvars] = j;
12119  nvars++;
12120  }
12121 
12122  /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
12123  * if too many variables are not fixed, then we do nothing currently
12124  */
12125  if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
12126  {
12127  SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
12128  SCIPfreeBufferArray(scip, &nonfixedpos);
12129  return SCIP_OKAY;
12130  }
12131 
12132  /* compute f(v^i) for each corner v^i of [l,u] */
12133  ncorners = POWEROFTWO(nvars);
12134  SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
12135  SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
12136  for( j = 0; j < nallvars; ++j )
12137  {
12138  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12139  corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
12140  }
12141  for( i = 0; i < ncorners; ++i )
12142  {
12143  SCIPdebugMsg(scip, "corner %u: ", i);
12144  for( j = 0; j < nvars; ++j )
12145  {
12146  int varpos = nonfixedpos[j];
12147  /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
12148  * we check this by shifting i for j positions to the right and checking whether the last bit is set
12149  */
12150  if( (i >> j) & 0x1 )
12151  corner[varpos] = box[2 * varpos + 1]; /* ub of var */
12152  else
12153  corner[varpos] = box[2 * varpos ]; /* lb of var */
12154  SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
12155  assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
12156  }
12157 
12158  funvals[i] = function(corner, nallvars, fundata);
12159 
12160  SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
12161 
12162  if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
12163  {
12164  SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
12165  goto CLEANUP;
12166  }
12167  }
12168 
12169  /* clear coefs array; below we only fill in coefs for nonfixed variables */
12170  BMSclearMemoryArray(facetcoefs, nallvars);
12171 
12172  if( nvars == 1 )
12173  {
12174  SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
12175 
12176  /* check whether target has been missed */
12177  if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
12178  {
12179  SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
12180  *success = FALSE;
12181  }
12182  }
12183  else if( nvars == 2 )
12184  {
12185  int idx1 = nonfixedpos[0];
12186  int idx2 = nonfixedpos[1];
12187  SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
12188  SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
12189  SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
12190  SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
12191  SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
12192  SCIP_Real coefs[2] = { 0.0, 0.0 };
12193 
12194  SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
12195 
12196  facetcoefs[idx1] = coefs[0];
12197  facetcoefs[idx2] = coefs[1];
12198  }
12199  else
12200  {
12201  SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
12202  }
12203  if( !*success )
12204  {
12205  SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
12206  goto CLEANUP;
12207  }
12208 
12209  /*
12210  * check and adjust facet with the algorithm of Rikun et al.
12211  */
12212 
12213  maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
12214 
12215  /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
12216  if( maxfaceterror > 0.0 )
12217  {
12218  SCIP_CONSHDLRDATA* conshdlrdata;
12219  SCIP_Real midval;
12220  SCIP_Real feastol;
12221 
12222  feastol = SCIPgetStage(scip) == SCIP_STAGE_SOLVING ? SCIPgetLPFeastol(scip) : SCIPfeastol(scip);
12223 
12224  /* evaluate function in middle point to get some idea for a scaling */
12225  for( j = 0; j < nvars; ++j )
12226  corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
12227  midval = function(corner, nallvars, fundata);
12228  if( midval == SCIP_INVALID )
12229  midval = 1.0;
12230 
12231  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12232  assert(conshdlrdata != NULL);
12233 
12234  /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
12235  if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
12236  {
12237  SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
12238  *success = FALSE;
12239  goto CLEANUP;
12240  }
12241 
12242  SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
12243 
12244  if( overestimate )
12245  *facetconstant += maxfaceterror;
12246  else
12247  *facetconstant -= maxfaceterror;
12248  }
12249 
12250  /* if we made it until here, then we have a nice facet */
12251  assert(*success);
12252 
12253 CLEANUP:
12254  /* free allocated memory */
12255  SCIPfreeBufferArray(scip, &corner);
12256  SCIPfreeBufferArray(scip, &funvals);
12257  SCIPfreeBufferArray(scip, &nonfixedpos);
12258 
12259  return SCIP_OKAY;
12260 }
12261 
12262 /*
12263  * constraint specific interface methods
12264  */
12265 
12266 /** returns the expression of the given nonlinear constraint */
12268  SCIP_CONS* cons /**< constraint data */
12269  )
12270 {
12271  SCIP_CONSDATA* consdata;
12272 
12273  assert(cons != NULL);
12274  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12275 
12276  consdata = SCIPconsGetData(cons);
12277  assert(consdata != NULL);
12278 
12279  return consdata->expr;
12280 }
12281 
12282 /** gets the left hand side of a nonlinear constraint */
12284  SCIP_CONS* cons /**< constraint data */
12285  )
12286 {
12287  SCIP_CONSDATA* consdata;
12288 
12289  assert(cons != NULL);
12290  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12291 
12292  consdata = SCIPconsGetData(cons);
12293  assert(consdata != NULL);
12294 
12295  return consdata->lhs;
12296 }
12297 
12298 /** gets the right hand side of a nonlinear constraint */
12300  SCIP_CONS* cons /**< constraint data */
12301  )
12302 {
12303  SCIP_CONSDATA* consdata;
12304 
12305  assert(cons != NULL);
12306  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12307 
12308  consdata = SCIPconsGetData(cons);
12309  assert(consdata != NULL);
12310 
12311  return consdata->rhs;
12312 }
12313 
12314 /** gets the nonlinear constraint as a nonlinear row representation. */
12316  SCIP* scip, /**< SCIP data structure */
12317  SCIP_CONS* cons, /**< constraint */
12318  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
12319  )
12320 {
12321  SCIP_CONSDATA* consdata;
12322 
12323  assert(cons != NULL);
12324  assert(nlrow != NULL);
12325  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12326 
12327  consdata = SCIPconsGetData(cons);
12328  assert(consdata != NULL);
12329 
12330  if( consdata->nlrow == NULL )
12331  {
12332  SCIP_CALL( createNlRow(scip, cons) );
12333  }
12334  assert(consdata->nlrow != NULL);
12335  *nlrow = consdata->nlrow;
12336 
12337  return SCIP_OKAY;
12338 }
12339 
12340 /** returns the curvature of the expression of a given nonlinear constraint
12341  *
12342  * @note The curvature information is computed during CONSINITSOL.
12343  */
12345  SCIP_CONS* cons /**< constraint data */
12346  )
12347 {
12348  SCIP_CONSDATA* consdata;
12349 
12350  assert(cons != NULL);
12351  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12352 
12353  consdata = SCIPconsGetData(cons);
12354  assert(consdata != NULL);
12355 
12356  return consdata->curv;
12357 }
12358 
12359 /** checks whether expression of constraint can be represented as quadratic form
12360  *
12361  * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
12362  * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
12363  * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
12364  */
12366  SCIP* scip, /**< SCIP data structure */
12367  SCIP_CONS* cons, /**< constraint data */
12368  SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
12369  )
12370 {
12371  SCIP_CONSDATA* consdata;
12372 
12373  assert(scip != NULL);
12374  assert(cons != NULL);
12375  assert(isquadratic != NULL);
12376  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12377 
12378  consdata = SCIPconsGetData(cons);
12379  assert(consdata != NULL);
12380  assert(consdata->expr != NULL);
12381 
12382  /* check whether constraint expression is quadratic in extended formulation */
12383  SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
12384 
12385  /* if not quadratic in non-extended formulation, then do indicate quadratic */
12386  if( *isquadratic )
12387  *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
12388 
12389  return SCIP_OKAY;
12390 }
12391 
12392 /** changes left-hand-side of a nonlinear constraint
12393  *
12394  * @attention This method can only be called in the problem stage.
12395  */
12397  SCIP* scip, /**< SCIP data structure */
12398  SCIP_CONS* cons, /**< constraint data */
12399  SCIP_Real lhs /**< new left-hand-side */
12400  )
12401 {
12402  SCIP_CONSDATA* consdata;
12403 
12404  assert(scip != NULL);
12405  assert(cons != NULL);
12406  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12407 
12408  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12409  {
12410  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12411  return SCIP_INVALIDCALL;
12412  }
12413 
12414  /* we should have an original constraint */
12415  assert(SCIPconsIsOriginal(cons));
12416 
12417  consdata = SCIPconsGetData(cons);
12418  assert(consdata != NULL);
12419 
12420  if( consdata->lhs == lhs )
12421  return SCIP_OKAY;
12422 
12423  consdata->lhs = lhs;
12424 
12425  /* not sure we care about any of these flags for original constraints */
12426  consdata->ispropagated = FALSE;
12427 
12428  return SCIP_OKAY;
12429 }
12430 
12431 /** changes right-hand-side of a nonlinear constraint
12432  *
12433  * @attention This method can only be called in the problem stage.
12434  */
12436  SCIP* scip, /**< SCIP data structure */
12437  SCIP_CONS* cons, /**< constraint data */
12438  SCIP_Real rhs /**< new right-hand-side */
12439  )
12440 {
12441  SCIP_CONSDATA* consdata;
12442 
12443  assert(scip != NULL);
12444  assert(cons != NULL);
12445  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12446 
12447  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12448  {
12449  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12450  return SCIP_INVALIDCALL;
12451  }
12452 
12453  /* we should have an original constraint */
12454  assert(SCIPconsIsOriginal(cons));
12455 
12456  consdata = SCIPconsGetData(cons);
12457  assert(consdata != NULL);
12458 
12459  if( consdata->rhs == rhs )
12460  return SCIP_OKAY;
12461 
12462  consdata->rhs = rhs;
12463 
12464  /* not sure we care about any of these flags for original constraints */
12465  consdata->ispropagated = FALSE;
12466 
12467  return SCIP_OKAY;
12468 }
12469 
12470 /** changes expression of a nonlinear constraint
12471  *
12472  * @attention This method can only be called in the problem stage.
12473  */
12475  SCIP* scip, /**< SCIP data structure */
12476  SCIP_CONS* cons, /**< constraint data */
12477  SCIP_EXPR* expr /**< new expression */
12478  )
12479 {
12480  SCIP_CONSHDLR* conshdlr;
12481  SCIP_CONSDATA* consdata;
12482 
12483  assert(scip != NULL);
12484  assert(cons != NULL);
12485  assert(expr != NULL);
12486 
12487  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12488  {
12489  SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
12490  return SCIP_INVALIDCALL;
12491  }
12492 
12493  /* we should have an original constraint */
12494  assert(SCIPconsIsOriginal(cons));
12495 
12496  conshdlr = SCIPconsGetHdlr(cons);
12497  assert(conshdlr != NULL);
12498  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12499 
12500  consdata = SCIPconsGetData(cons);
12501  assert(consdata != NULL);
12502  assert(consdata->expr != NULL);
12503 
12504  /* we should not have collected additional data for the expr
12505  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12506  */
12507  assert(consdata->nvarexprs == 0);
12508  assert(consdata->varexprs == NULL);
12509  assert(!consdata->catchedevents);
12510 
12511  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
12512 
12513  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12514  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12515 
12516  /* not sure we care about any of these flags for original constraints */
12517  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
12518  consdata->issimplified = FALSE;
12519  consdata->ispropagated = FALSE;
12520 
12521  return SCIP_OKAY;
12522 }
12523 
12524 /** adds coef * var to nonlinear constraint
12525  *
12526  * @attention This method can only be called in the problem stage.
12527  */
12529  SCIP* scip, /**< SCIP data structure */
12530  SCIP_CONS* cons, /**< constraint data */
12531  SCIP_VAR* var, /**< variable */
12532  SCIP_Real coef /**< coefficient */
12533  )
12534 {
12535  SCIP_CONSHDLR* conshdlr;
12536  SCIP_CONSDATA* consdata;
12537  SCIP_EXPR* varexpr;
12538 
12539  assert(scip != NULL);
12540  assert(cons != NULL);
12541 
12542  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12543  {
12544  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12545  return SCIP_INVALIDCALL;
12546  }
12547 
12548  /* we should have an original constraint */
12549  assert(SCIPconsIsOriginal(cons));
12550 
12551  if( coef == 0.0 )
12552  return SCIP_OKAY;
12553 
12554  conshdlr = SCIPconsGetHdlr(cons);
12555  assert(conshdlr != NULL);
12556  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12557 
12558  consdata = SCIPconsGetData(cons);
12559  assert(consdata != NULL);
12560  assert(consdata->expr != NULL);
12561 
12562  /* we should not have collected additional data for it
12563  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12564  */
12565  assert(consdata->nvarexprs == 0);
12566  assert(consdata->varexprs == NULL);
12567  assert(!consdata->catchedevents);
12568 
12569  SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
12570 
12571  /* append to sum, if consdata->expr is sum and not used anywhere else */
12572  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12573  {
12574  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
12575  }
12576  else
12577  {
12578  /* create new expression = 1 * consdata->expr + coef * var */
12579  SCIP_EXPR* children[2] = { consdata->expr, varexpr };
12580  SCIP_Real coefs[2] = { 1.0, coef };
12581 
12582  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12583 
12584  /* release old root expr */
12585  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12586  }
12587 
12588  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12589 
12590  /* not sure we care about any of these flags for original constraints */
12591  consdata->issimplified = FALSE;
12592  consdata->ispropagated = FALSE;
12593 
12594  return SCIP_OKAY;
12595 }
12596 
12597 /** adds coef * expr to nonlinear constraint
12598  *
12599  * @attention This method can only be called in the problem stage.
12600  */
12602  SCIP* scip, /**< SCIP data structure */
12603  SCIP_CONS* cons, /**< nonlinear constraint */
12604  SCIP_EXPR* expr, /**< expression */
12605  SCIP_Real coef /**< coefficient */
12606  )
12607 {
12608  SCIP_CONSHDLR* conshdlr;
12609  SCIP_CONSDATA* consdata;
12610  SCIP_EXPR* exprowned;
12611 
12612  assert(scip != NULL);
12613  assert(cons != NULL);
12614 
12615  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12616  {
12617  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12618  return SCIP_INVALIDCALL;
12619  }
12620 
12621  /* we should have an original constraint */
12622  assert(SCIPconsIsOriginal(cons));
12623 
12624  if( coef == 0.0 )
12625  return SCIP_OKAY;
12626 
12627  conshdlr = SCIPconsGetHdlr(cons);
12628  assert(conshdlr != NULL);
12629  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12630 
12631  consdata = SCIPconsGetData(cons);
12632  assert(consdata != NULL);
12633  assert(consdata->expr != NULL);
12634 
12635  /* we should not have collected additional data for it
12636  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12637  */
12638  assert(consdata->nvarexprs == 0);
12639  assert(consdata->varexprs == NULL);
12640  assert(!consdata->catchedevents);
12641 
12642  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12643  SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12644 
12645  /* append to sum, if consdata->expr is sum and not used anywhere else */
12646  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12647  {
12648  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
12649  }
12650  else
12651  {
12652  /* create new expression = 1 * consdata->expr + coef * var */
12653  SCIP_EXPR* children[2] = { consdata->expr, exprowned };
12654  SCIP_Real coefs[2] = { 1.0, coef };
12655 
12656  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12657 
12658  /* release old root expr */
12659  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12660  }
12661 
12662  SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
12663 
12664  /* not sure we care about any of these flags for original constraints */
12665  consdata->issimplified = FALSE;
12666  consdata->ispropagated = FALSE;
12667 
12668  return SCIP_OKAY;
12669 }
12670 
12671 /** gets absolute violation of nonlinear constraint
12672  *
12673  * This function evaluates the constraints in the given solution.
12674  *
12675  * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
12676  */
12678  SCIP* scip, /**< SCIP data structure */
12679  SCIP_CONS* cons, /**< constraint */
12680  SCIP_SOL* sol, /**< solution to check */
12681  SCIP_Real* viol /**< buffer to store computed violation */
12682  )
12683 {
12684  assert(cons != NULL);
12685  assert(viol != NULL);
12686 
12687  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12688  *viol = getConsAbsViolation(cons);
12689 
12690  return SCIP_OKAY;
12691 }
12692 
12693 /** gets scaled violation of nonlinear constraint
12694  *
12695  * This function evaluates the constraints in the given solution.
12696  *
12697  * The scaling that is applied to the absolute violation of the constraint
12698  * depends on the setting of parameter constraints/nonlinear/violscale.
12699  */
12701  SCIP* scip, /**< SCIP data structure */
12702  SCIP_CONS* cons, /**< constraint */
12703  SCIP_SOL* sol, /**< solution to check */
12704  SCIP_Real* viol /**< buffer to store computed violation */
12705  )
12706 {
12707  assert(cons != NULL);
12708  assert(viol != NULL);
12709 
12710  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12711  SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
12712 
12713  return SCIP_OKAY;
12714 }
12715 
12716 /** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
12718  SCIP* scip, /**< SCIP data structure */
12719  SCIP_CONS* cons, /**< nonlinear constraint */
12720  SCIP_VAR** var, /**< pointer to store the variable */
12721  SCIP_Real* coef /**< pointer to store the coefficient */
12722  )
12723 {
12724  SCIP_CONSDATA* consdata;
12725 
12726  assert(cons != NULL);
12727  assert(var != NULL);
12728  assert(coef != NULL);
12729 
12730  /* check for a linear variable that can be increased or decreased without harming feasibility */
12731  findUnlockedLinearVar(scip, cons);
12732 
12733  consdata = SCIPconsGetData(cons);
12734  assert(consdata != NULL);
12735 
12736  *var = consdata->linvardecr;
12737  *coef = consdata->linvardecrcoef;
12738 }
12739 
12740 /** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
12742  SCIP* scip, /**< SCIP data structure */
12743  SCIP_CONS* cons, /**< nonlinear constraint */
12744  SCIP_VAR** var, /**< pointer to store the variable */
12745  SCIP_Real* coef /**< pointer to store the coefficient */
12746  )
12747 {
12748  SCIP_CONSDATA* consdata;
12749 
12750  assert(cons != NULL);
12751  assert(var != NULL);
12752  assert(coef != NULL);
12753 
12754  /* check for a linear variable that can be increased or decreased without harming feasibility */
12755  findUnlockedLinearVar(scip, cons);
12756 
12757  consdata = SCIPconsGetData(cons);
12758  assert(consdata != NULL);
12759 
12760  *var = consdata->linvarincr;
12761  *coef = consdata->linvarincrcoef;
12762 }
12763 
12764 
12765 /*
12766  * Methods for Expressions in Nonlinear Constraints
12767  */
12768 
12769 /** returns the number of positive rounding locks of an expression */
12771  SCIP_EXPR* expr /**< expression */
12772  )
12773 {
12774  assert(expr != NULL);
12775  assert(SCIPexprGetOwnerData(expr) != NULL);
12776 
12777  return SCIPexprGetOwnerData(expr)->nlockspos;
12778 }
12779 
12780 /** returns the number of negative rounding locks of an expression */
12782  SCIP_EXPR* expr /**< expression */
12783  )
12784 {
12785  assert(expr != NULL);
12786  assert(SCIPexprGetOwnerData(expr) != NULL);
12787 
12788  return SCIPexprGetOwnerData(expr)->nlocksneg;
12789 }
12790 
12791 /** returns the variable used for linearizing a given expression (return value might be NULL)
12792  *
12793  * @note for variable expression it returns the corresponding variable
12794  */
12796  SCIP_EXPR* expr /**< expression */
12797  )
12798 {
12799  SCIP_EXPR_OWNERDATA* ownerdata;
12800 
12801  assert(expr != NULL);
12802 
12803  ownerdata = SCIPexprGetOwnerData(expr);
12804  assert(ownerdata != NULL);
12805 
12806  return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
12807 }
12808 
12809 /** returns the number of enforcements for an expression */
12811  SCIP_EXPR* expr /**< expression */
12812  )
12813 {
12814  assert(expr != NULL);
12815  assert(SCIPexprGetOwnerData(expr) != NULL);
12816 
12817  return SCIPexprGetOwnerData(expr)->nenfos;
12818 }
12819 
12820 /** returns the data for one of the enforcements of an expression */
12822  SCIP_EXPR* expr, /**< expression */
12823  int idx, /**< position of enforcement in enfos array */
12824  SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
12825  SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
12826  SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
12827  SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
12828  SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
12829  SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
12830  )
12831 {
12832  SCIP_EXPR_OWNERDATA* ownerdata;
12833 
12834  assert(expr != NULL);
12835 
12836  ownerdata = SCIPexprGetOwnerData(expr);
12837  assert(ownerdata != NULL);
12838  assert(idx >= 0);
12839  assert(idx < ownerdata->nenfos);
12840  assert(ownerdata->enfos[idx] != NULL);
12841  assert(nlhdlr != NULL);
12842 
12843  *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
12844 
12845  if( nlhdlrexprdata != NULL )
12846  *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
12847 
12848  if( nlhdlrparticipation != NULL )
12849  *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
12850 
12851  if( sepabelowusesactivity != NULL )
12852  *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
12853 
12854  if( sepaaboveusesactivity != NULL )
12855  *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
12856 
12857  if( auxvalue != NULL )
12858  *auxvalue = ownerdata->enfos[idx]->auxvalue;
12859 }
12860 
12861 /** sets the auxiliary value of expression for one of the enforcements of an expression */
12863  SCIP_EXPR* expr, /**< expression */
12864  int idx, /**< position of enforcement in enfos array */
12865  SCIP_Real auxvalue /**< the new value of auxval */
12866  )
12867 {
12868  SCIP_EXPR_OWNERDATA* ownerdata;
12869 
12870  assert(expr != NULL);
12871 
12872  ownerdata = SCIPexprGetOwnerData(expr);
12873  assert(ownerdata != NULL);
12874 
12875  assert(idx >= 0);
12876  assert(idx < ownerdata->nenfos);
12877  assert(ownerdata->enfos[idx] != NULL);
12878 
12879  ownerdata->enfos[idx]->auxvalue = auxvalue;
12880 }
12881 
12882 /** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
12883  *
12884  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12885  */
12887  SCIP_EXPR* expr /**< expression */
12888  )
12889 {
12890  assert(expr != NULL);
12891  assert(SCIPexprGetOwnerData(expr) != NULL);
12892 
12893  return SCIPexprGetOwnerData(expr)->nactivityusesprop;
12894 }
12895 
12896 /** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
12897  *
12898  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12899  */
12901  SCIP_EXPR* expr /**< expression */
12902  )
12903 {
12904  assert(expr != NULL);
12905  assert(SCIPexprGetOwnerData(expr) != NULL);
12906 
12907  return SCIPexprGetOwnerData(expr)->nactivityusessepa;
12908 }
12909 
12910 /** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
12911  *
12912  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12913  */
12914 unsigned int SCIPgetExprNAuxvarUsesNonlinear(
12915  SCIP_EXPR* expr /**< expression */
12916  )
12917 {
12918  assert(expr != NULL);
12919  assert(SCIPexprGetOwnerData(expr) != NULL);
12920 
12921  return SCIPexprGetOwnerData(expr)->nauxvaruses;
12922 }
12923 
12924 /** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
12925  *
12926  * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
12927  * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
12928  * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
12929  * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
12930  * and also increments this count for all variables in the expression.
12931  *
12932  * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
12933  * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
12934  * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
12935  * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
12936  */
12938  SCIP* scip, /**< SCIP data structure */
12939  SCIP_EXPR* expr, /**< expression */
12940  SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
12941  SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
12942  SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
12943  SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
12944  )
12945 {
12946  SCIP_EXPR_OWNERDATA* ownerdata;
12947 
12948  assert(expr != NULL);
12949 
12950  ownerdata = SCIPexprGetOwnerData(expr);
12951  assert(ownerdata != NULL);
12952 
12953  /* do not store auxvar request for variable expressions */
12954  if( useauxvar && SCIPisExprVar(scip, expr) )
12955  useauxvar = FALSE;
12956 
12957  if( ownerdata->nenfos >= 0 &&
12958  ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
12959  (ownerdata->nauxvaruses == 0 && useauxvar)
12960  ) )
12961  {
12962  /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
12963  * we require additional enforcement methods, that is,
12964  * - activity of expr was not used before but will be used now, or
12965  * - auxiliary variable of expr was not required before but will be used now
12966  */
12967  SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
12968  }
12969 
12970  if( useauxvar )
12971  ++ownerdata->nauxvaruses;
12972 
12973  if( useactivityforprop )
12974  ++ownerdata->nactivityusesprop;
12975 
12976  if( useactivityforsepabelow || useactivityforsepaabove )
12977  ++ownerdata->nactivityusessepa;
12978 
12979  /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
12980  * information is used in detectNlhdlr()
12981  */
12982  if( useactivityforsepabelow )
12983  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
12984  if( useactivityforsepaabove )
12985  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
12986 
12987  if( useactivityforprop )
12988  {
12989  /* if activity will be used for propagation, then make sure there is a valid activity
12990  * this way, we can do a reversepropcall after detectNlhdlr
12991  */
12992  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
12993  }
12994 
12995  /* increase the nactivityusedsepa counter for all variables used in the given expression */
12996  if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
12997  {
12998  SCIP_EXPRITER* it;
12999 
13000  /* create and initialize iterator */
13001  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13003 
13004  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13005  if( SCIPisExprVar(scip, expr) )
13006  ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
13007 
13008  /* free iterator */
13009  SCIPfreeExpriter(&it);
13010  }
13011 
13012  return SCIP_OKAY;
13013 }
13014 
13015 /** computes absolute violation for auxvar relation in an expression w.r.t. original variables
13016  *
13017  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
13018  * Assume that f(x) is associated with auxiliary variable z.
13019  *
13020  * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
13021  * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
13022  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
13023  *
13024  * If necessary, f is evaluated in the given solution. If that fails (domain error),
13025  * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
13026  */
13028  SCIP* scip, /**< SCIP data structure */
13029  SCIP_EXPR* expr, /**< expression */
13030  SCIP_SOL* sol, /**< solution */
13031  SCIP_Longint soltag, /**< tag of solution */
13032  SCIP_Real* viol, /**< buffer to store computed violation */
13033  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
13034  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
13035  )
13036 {
13037  assert(scip != NULL);
13038  assert(expr != NULL);
13039  assert(viol != NULL);
13040 
13041  /* make sure expression has been evaluated */
13042  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
13043 
13044  /* get violation from internal method */
13045  *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
13046 
13047  return SCIP_OKAY;
13048 }
13049 
13050 /** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
13051  *
13052  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13053  * Assume that f(w) is associated with auxiliary variable z.
13054  *
13055  * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
13056  * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
13057  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
13058  *
13059  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13060  * both `violover` and `violunder` are set to TRUE.
13061  */
13063  SCIP* scip, /**< SCIP data structure */
13064  SCIP_EXPR* expr, /**< expression */
13065  SCIP_Real auxvalue, /**< the value of f(w) */
13066  SCIP_SOL* sol, /**< solution that has been evaluated */
13067  SCIP_Real* viol, /**< buffer to store computed violation */
13068  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13069  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13070  )
13071 {
13072  assert(scip != NULL);
13073  assert(expr != NULL);
13074  assert(viol != NULL);
13075 
13076  /* get violation from internal method */
13077  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13078 
13079  return SCIP_OKAY;
13080 }
13081 
13082 
13083 /** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
13084  *
13085  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13086  * Assume that f(w) is associated with auxiliary variable z.
13087  *
13088  * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
13089  * the absolute violation divided by max(1,|f(w)|).
13090  *
13091  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13092  * both `violover` and `violunder` are set to TRUE.
13093  */
13095  SCIP* scip, /**< SCIP data structure */
13096  SCIP_EXPR* expr, /**< expression */
13097  SCIP_Real auxvalue, /**< the value of f(w) */
13098  SCIP_SOL* sol, /**< solution that has been evaluated */
13099  SCIP_Real* viol, /**< buffer to store computed violation */
13100  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13101  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13102  )
13103 {
13104  assert(scip != NULL);
13105  assert(expr != NULL);
13106  assert(viol != NULL);
13107 
13108  /* get violation from internal method */
13109  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13110 
13111  if( !SCIPisInfinity(scip, *viol) )
13112  {
13113  assert(auxvalue != SCIP_INVALID);
13114  /* TODO maybe we should rather use max(eps,|auxvalue|)? */
13115  *viol /= MAX(1.0, REALABS(auxvalue));
13116  }
13117 
13118  return SCIP_OKAY;
13119 }
13120 
13121 /** returns bounds on the expression
13122  *
13123  * This gives an intersection of bounds from
13124  * - activity calculation (SCIPexprGetActivity()), if valid,
13125  * - auxiliary variable, if present,
13126  * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
13127  *
13128  * @note The returned interval can be empty!
13129  */
13131  SCIP* scip, /**< SCIP data structure */
13132  SCIP_EXPR* expr /**< expression */
13133  )
13134 {
13135  SCIP_EXPR_OWNERDATA* ownerdata;
13136  SCIP_CONSHDLRDATA* conshdlrdata;
13137  SCIP_INTERVAL bounds;
13138 
13139  assert(scip != NULL);
13140  assert(expr != NULL);
13141 
13142  ownerdata = SCIPexprGetOwnerData(expr);
13143  assert(ownerdata != NULL);
13144 
13145  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13146  assert(conshdlrdata != NULL);
13147 
13148  /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
13149 
13150  /* start with propbounds if they belong to current propagation */
13151  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13152  {
13153  bounds = ownerdata->propbounds;
13154  /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
13155  }
13156  else
13158 
13159  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
13160  {
13161  /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
13162  /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
13163  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), bounds);
13164  }
13165 
13166  if( ownerdata->auxvar != NULL )
13167  {
13168  /* apply auxiliary variable bounds to bounds */
13169  SCIP_INTERVAL auxvarbounds;
13170 
13171  auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
13172  /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
13173  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
13174  }
13175 
13176  /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
13177 
13178  return bounds;
13179 }
13180 
13181 /** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
13182  * corresponding (auxiliary) variable (if any)
13183  *
13184  * @attention this function should only be called during domain propagation in cons_nonlinear
13185  */
13187  SCIP* scip, /**< SCIP data structure */
13188  SCIP_EXPR* expr, /**< expression to be tightened */
13189  SCIP_INTERVAL newbounds, /**< new bounds for the expression */
13190  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
13191  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
13192  )
13193 {
13194  SCIP_EXPR_OWNERDATA* ownerdata;
13195  SCIP_CONSHDLRDATA* conshdlrdata;
13196 
13197  assert(scip != NULL);
13198  assert(expr != NULL);
13199  assert(cutoff != NULL);
13200 
13201  ownerdata = SCIPexprGetOwnerData(expr);
13202  assert(ownerdata != NULL);
13203  assert(ownerdata->conshdlr != NULL);
13204 
13205  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13206  assert(conshdlrdata != NULL);
13207 
13208  /* the code below assumes that current activity is valid
13209  * if it turns out that we cannot ensure that, then we should change code
13210  */
13211  assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13213 
13214  *cutoff = FALSE;
13215 
13216 #ifdef DEBUG_PROP
13217  SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
13218  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
13219  SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
13220 #endif
13221 
13222  if( SCIPexprIsIntegral(expr) )
13223  {
13224  /* apply integrality to new bounds
13225  * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
13226  */
13227  if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
13228  newbounds.inf = SCIPceil(scip, newbounds.inf);
13229  if( newbounds.sup < SCIP_INTERVAL_INFINITY )
13230  newbounds.sup = SCIPfloor(scip, newbounds.sup);
13231 #ifdef DEBUG_PROP
13232  SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
13233 #endif
13234  }
13235 
13237  {
13238  SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
13239 
13240  *cutoff = TRUE;
13241  return SCIP_OKAY;
13242  }
13243 
13244  /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
13245  if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
13246  {
13247  SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
13248 
13249  *cutoff = TRUE;
13250  return SCIP_OKAY;
13251  }
13252 
13253  /* tighten newbounds w.r.t. existing expr->propbounds or activity */
13254  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13255  {
13256  /* if already having propbounds in expr, then tighten newbounds by propbounds */
13257  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
13258  }
13259  else
13260  {
13261  /* first time we have propbounds for expr in this propagation rounds:
13262  * intersect with activity (though don't let it become empty if very close intervals)
13263  */
13264  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
13265  }
13266 #ifdef DEBUG_PROP
13267  SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
13268 #endif
13269 
13270  /* check if the new bounds lead to an empty interval */
13272  {
13273  SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
13274 
13275  *cutoff = TRUE;
13276  return SCIP_OKAY;
13277  }
13278 
13279  /* if expr is not constant or variable, then store newbounds in expr->propbounds
13280  * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
13281  * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
13282  */
13283  if( SCIPexprGetNChildren(expr) > 0 )
13284  {
13285  ownerdata->propbounds = newbounds;
13286  ownerdata->propboundstag = conshdlrdata->curpropboundstag;
13287  }
13288 
13289  /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
13290  * propagation or update of auxvar bounds
13291  * TODO? if we first had a considerable tightening and then only get small tightenings under the same
13292  * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
13293  * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
13294  * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
13295  * one or should we not even update propbounds to newbounds if the update is small?
13296  */
13297  if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
13298  {
13299 #ifdef DEBUG_PROP
13300  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);
13301 #endif
13302  return SCIP_OKAY;
13303  }
13304 
13305  if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
13306  {
13307  /* add expression to propagation queue if not there yet and not var or constant and
13308  * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
13309  */
13310 #ifdef DEBUG_PROP
13311  SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
13312 #endif
13313  SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
13314  ownerdata->inpropqueue = TRUE;
13315  }
13316 
13317  /* update bounds on variable or auxiliary variable */
13318  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
13319 
13320  return SCIP_OKAY;
13321 }
13322 
13323 /** mark constraints that include this expression to be propagated again
13324  *
13325  * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
13326  * a change of variable bounds, e.g., because new information on the expression is available
13327  * that could potentially lead to tighter expression activity values.
13328  *
13329  * Note, that this call marks also constraints for propagation which only share some variable
13330  * with this expression.
13331  */
13333  SCIP* scip, /**< SCIP data structure */
13334  SCIP_EXPR* expr /**< expression to propagate again */
13335  )
13336 {
13337  SCIP_EXPRITER* it;
13338  SCIP_CONSDATA* consdata;
13339  SCIP_EXPR_OWNERDATA* ownerdata;
13340  int c;
13341 
13342  assert(scip != NULL);
13343  assert(expr != NULL);
13344 
13345  ownerdata = SCIPexprGetOwnerData(expr);
13346  assert(ownerdata != NULL);
13347 
13348  SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
13349 
13350  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13352 
13353  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13354  {
13355  if( !SCIPisExprVar(scip, expr) )
13356  continue;
13357 
13358  ownerdata = SCIPexprGetOwnerData(expr);
13359  assert(ownerdata != NULL);
13360 
13361  for( c = 0; c < ownerdata->nconss; ++c )
13362  {
13363  consdata = SCIPconsGetData(ownerdata->conss[c]);
13364  assert(consdata != NULL);
13365  consdata->ispropagated = FALSE;
13366  }
13367  }
13368 
13369  SCIPfreeExpriter(&it);
13370 
13371  return SCIP_OKAY;
13372 }
13373 
13374 /** adds violation-branching score to an expression
13375  *
13376  * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
13377  * The expression must either be a variable expression or have an aux-variable.
13378  * In the latter case, branching on auxiliary variables must have been enabled.
13379  * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
13380  * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
13381  * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
13382  *
13383  * @see SCIPaddExprsViolScoreNonlinear()
13384  */
13386  SCIP* scip, /**< SCIP data structure */
13387  SCIP_EXPR* expr, /**< expression where to add branching score */
13388  SCIP_Real violscore /**< violation score to add to expression */
13389  )
13390 {
13391  SCIP_EXPR_OWNERDATA* ownerdata;
13392  SCIP_CONSHDLRDATA* conshdlrdata;
13393 
13394  assert(scip != NULL);
13395  assert(expr != NULL);
13396  assert(violscore >= 0.0);
13397 
13398  ownerdata = SCIPexprGetOwnerData(expr);
13399  assert(ownerdata != NULL);
13400 
13401  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13402  assert(conshdlrdata != NULL);
13403 
13404  /* if not allowing to branch on auxvars, then expr must be a var-expr */
13405  assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
13406  /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
13407  assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
13408 
13409  /* reset branching score if we are in a different enfo round */
13410  if( ownerdata->violscoretag != conshdlrdata->enforound )
13411  {
13412  ownerdata->violscoresum = violscore;
13413  ownerdata->violscoremax = violscore;
13414  ownerdata->nviolscores = 1;
13415  ownerdata->violscoretag = conshdlrdata->enforound;
13416  return;
13417  }
13418 
13419  ownerdata->violscoresum += violscore;
13420  if( violscore > ownerdata->violscoremax )
13421  ownerdata->violscoremax = violscore;
13422  ++ownerdata->nviolscores;
13423 }
13424 
13425 /** adds violation-branching score to a set of expressions, distributing the score among all the expressions
13426  *
13427  * Each expression must either be a variable expression or have an aux-variable.
13428  * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
13429  * variables present in `exprs`.
13430  */
13432  SCIP* scip, /**< SCIP data structure */
13433  SCIP_EXPR** exprs, /**< expressions where to add branching score */
13434  int nexprs, /**< number of expressions */
13435  SCIP_Real violscore, /**< violation score to add to expression */
13436  SCIP_SOL* sol, /**< current solution */
13437  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
13438  )
13439 {
13440  SCIP_EXPRITER* it;
13441  SCIP_EXPR** varexprs;
13442  SCIP_EXPR* e;
13443  int nvars;
13444  int varssize;
13445  int i;
13446 
13447  assert(exprs != NULL || nexprs == 0);
13448  assert(success != NULL);
13449 
13450  if( nexprs == 0 )
13451  {
13452  *success = FALSE;
13453  return SCIP_OKAY;
13454  }
13455 
13456  /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
13457  if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
13458  {
13459  addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
13460  return SCIP_OKAY;
13461  }
13462 
13463  /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
13464  nvars = 0;
13465  varssize = 5;
13466  SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
13467 
13468  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13470 
13471  for( i = 0; i < nexprs; ++i )
13472  {
13473  for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
13474  {
13475  assert(e != NULL);
13476 
13477  if( SCIPisExprVar(scip, e) )
13478  {
13479  /* add variable expression to vars array */
13480  if( varssize == nvars )
13481  {
13482  varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
13483  SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
13484  }
13485  assert(varssize > nvars);
13486 
13487  varexprs[nvars++] = e;
13488  }
13489  }
13490  }
13491 
13492  SCIPfreeExpriter(&it);
13493 
13494  addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
13495 
13496  SCIPfreeBufferArray(scip, &varexprs);
13497 
13498  return SCIP_OKAY;
13499 }
13500 
13501 /** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
13503  SCIP_EXPR* expr /**< expression */
13504  )
13505 {
13506  SCIP_EXPR_OWNERDATA* ownerdata;
13507  SCIP_CONSHDLRDATA* conshdlrdata;
13508 
13509  assert(expr != NULL);
13510 
13511  ownerdata = SCIPexprGetOwnerData(expr);
13512  assert(ownerdata != NULL);
13513 
13514  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13515  assert(conshdlrdata != NULL);
13516 
13517  if( conshdlrdata->enforound != ownerdata->violscoretag )
13518  return 0.0;
13519 
13520  if( ownerdata->nviolscores == 0 )
13521  return 0.0;
13522 
13523  switch( conshdlrdata->branchscoreagg )
13524  {
13525  case 'a' :
13526  /* average */
13527  return ownerdata->violscoresum / ownerdata->nviolscores;
13528 
13529  case 'm' :
13530  /* maximum */
13531  return ownerdata->violscoremax;
13532 
13533  case 's' :
13534  /* sum */
13535  return ownerdata->violscoresum;
13536 
13537  default:
13538  SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
13539  SCIPABORT();
13540  return SCIP_INVALID;
13541  }
13542 }
13543 
13544 /** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13545  *
13546  * @see SCIPexprGetDerivative()
13547  */
13549  SCIP* scip, /**< SCIP data structure */
13550  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
13551  SCIP_VAR* var /**< variable (needs to be in the expression) */
13552  )
13553 {
13554  SCIP_EXPR_OWNERDATA* ownerdata;
13555  SCIP_CONSHDLRDATA* conshdlrdata;
13556  SCIP_EXPR* varexpr;
13557 
13558  assert(scip != NULL);
13559  assert(expr != NULL);
13560  assert(var != NULL);
13561 
13562  /* return 0.0 for value expression */
13563  if( SCIPisExprValue(scip, expr) )
13564  {
13565  assert(SCIPexprGetDerivative(expr) == 0.0);
13566  return 0.0;
13567  }
13568 
13569  /* check if an error occurred during the last SCIPevalExprGradient() call */
13570  if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
13571  return SCIP_INVALID;
13572 
13573  ownerdata = SCIPexprGetOwnerData(expr);
13574  assert(ownerdata != NULL);
13575 
13576  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13577  assert(conshdlrdata != NULL);
13578 
13579  /* use variable to expressions mapping which is stored in the constraint handler data */
13580  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13581 
13582  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13583  assert(varexpr != NULL);
13584  assert(SCIPisExprVar(scip, varexpr));
13585 
13586  /* use difftag to decide whether the variable belongs to the expression */
13587  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
13588 }
13589 
13590 /** 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)
13591  *
13592  * @see SCIPexprGetBardot()
13593  */
13595  SCIP* scip, /**< SCIP data structure */
13596  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
13597  SCIP_VAR* var /**< variable (needs to be in the expression) */
13598  )
13599 {
13600  SCIP_EXPR_OWNERDATA* ownerdata;
13601  SCIP_CONSHDLRDATA* conshdlrdata;
13602  SCIP_EXPR* varexpr;
13603 
13604  assert(scip != NULL);
13605  assert(expr != NULL);
13606  assert(var != NULL);
13607 
13608  /* return 0.0 for value expression */
13609  if( SCIPisExprValue(scip, expr) )
13610  return 0.0;
13611 
13612  /* check if an error occurred during the last SCIPevalExprHessianDir() call */
13613  if( SCIPexprGetBardot(expr) == SCIP_INVALID )
13614  return SCIP_INVALID;
13615 
13616  ownerdata = SCIPexprGetOwnerData(expr);
13617  assert(ownerdata != NULL);
13618 
13619  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13620  assert(conshdlrdata != NULL);
13621 
13622  /* use variable to expressions mapping which is stored in the constraint handler data;
13623  * if this fails it means that we are asking for the var's component of H*u for a var
13624  * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
13625  */
13626  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13627 
13628  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13629  assert(varexpr != NULL);
13630  assert(SCIPisExprVar(scip, varexpr));
13631 
13632  /* use difftag to decide whether the variable belongs to the expression */
13633  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
13634 }
13635 
13636 /** evaluates quadratic term in a solution w.r.t. auxiliary variables
13637  *
13638  * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
13639  */
13641  SCIP* scip, /**< SCIP data structure */
13642  SCIP_EXPR* expr, /**< quadratic expression */
13643  SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
13644  )
13645 {
13646  SCIP_Real auxvalue;
13647  int nlinexprs;
13648  SCIP_Real* lincoefs;
13649  SCIP_EXPR** linexprs;
13650  int nquadexprs;
13651  int nbilinexprs;
13652  int i;
13653 
13654  assert(scip != NULL);
13655  assert(expr != NULL);
13656 
13657  SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
13658 
13659  /* linear terms */
13660  for( i = 0; i < nlinexprs; ++i )
13661  {
13662  assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
13663  auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
13664  }
13665 
13666  /* quadratic terms */
13667  for( i = 0; i < nquadexprs; ++i )
13668  {
13669  SCIP_EXPR* quadexprterm;
13670  SCIP_Real lincoef;
13671  SCIP_Real sqrcoef;
13672  SCIP_Real solval;
13673 
13674  SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
13675 
13676  assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
13677 
13678  solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
13679  auxvalue += (lincoef + sqrcoef * solval) * solval;
13680  }
13681 
13682  /* bilinear terms */
13683  for( i = 0; i < nbilinexprs; ++i )
13684  {
13685  SCIP_EXPR* expr1;
13686  SCIP_EXPR* expr2;
13687  SCIP_Real coef;
13688 
13689  SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
13690 
13691  assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
13692  assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
13693  auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
13694  }
13695 
13696  return auxvalue;
13697 }
13698 
13699 /**@addtogroup PublicNlhdlrInterfaceMethods
13700  * @{
13701  */
13702 
13703 /** creates a nonlinear handler and includes it into the nonlinear constraint handler */
13705  SCIP* scip, /**< SCIP data structure */
13706  SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
13707  const char* name, /**< name of nonlinear handler (must not be NULL) */
13708  const char* desc, /**< description of nonlinear handler (can be NULL) */
13709  int detectpriority, /**< detection priority of nonlinear handler */
13710  int enfopriority, /**< enforcement priority of nonlinear handler */
13711  SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
13712  SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
13713  SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
13714  )
13715 {
13716  SCIP_CONSHDLR* conshdlr;
13717  SCIP_CONSHDLRDATA* conshdlrdata;
13718 
13719  assert(scip != NULL);
13720  assert(nlhdlr != NULL);
13721  assert(detect != NULL);
13722 
13723  /* find myself */
13724  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13725  if( conshdlr == NULL )
13726  {
13727  SCIPerrorMessage("nonlinear constraint handler not found");
13728  return SCIP_PLUGINNOTFOUND;
13729  }
13730 
13731  /* create nlhdlr */
13732  SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
13733 
13734  /* include into constraint handler */
13735  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13736  assert(conshdlrdata != NULL);
13737 
13738  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
13739 
13740  conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
13741  ++conshdlrdata->nnlhdlrs;
13742 
13743  /* sort nonlinear handlers by detection priority, in decreasing order
13744  * will happen in INIT, so only do when called late
13745  */
13746  if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
13747  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
13748 
13749  return SCIP_OKAY;
13750 }
13751 
13752 /** get number of nonlinear handler */
13754  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13755  )
13756 {
13757  SCIP_CONSHDLRDATA* conshdlrdata;
13758 
13759  assert(conshdlr != NULL);
13760 
13761  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13762  assert(conshdlrdata != NULL);
13763 
13764  return conshdlrdata->nnlhdlrs;
13765 }
13766 
13767 /** get nonlinear handlers */
13769  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13770  )
13771 {
13772  SCIP_CONSHDLRDATA* conshdlrdata;
13773 
13774  assert(conshdlr != NULL);
13775 
13776  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13777  assert(conshdlrdata != NULL);
13778 
13779  return conshdlrdata->nlhdlrs;
13780 }
13781 
13782 /** returns a nonlinear handler of a given name (or NULL if not found) */
13784  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13785  const char* name /**< name of nonlinear handler */
13786  )
13787 {
13788  SCIP_CONSHDLRDATA* conshdlrdata;
13789  int h;
13790 
13791  assert(conshdlr != NULL);
13792  assert(name != NULL);
13793 
13794  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13795  assert(conshdlrdata != NULL);
13796 
13797  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
13798  if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
13799  return conshdlrdata->nlhdlrs[h];
13800 
13801  return NULL;
13802 }
13803 
13804 /** gives expression data that a given nonlinear handler stored in an expression
13805  *
13806  * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
13807  */
13809  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
13810  SCIP_EXPR* expr /**< expression */
13811  )
13812 {
13813  SCIP_EXPR_OWNERDATA* ownerdata;
13814  int e;
13815 
13816  assert(nlhdlr != NULL);
13817  assert(expr != NULL);
13818 
13819  ownerdata = SCIPexprGetOwnerData(expr);
13820  assert(ownerdata != NULL);
13821 
13822  for( e = 0; e < ownerdata->nenfos; ++e )
13823  if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
13824  return ownerdata->enfos[e]->nlhdlrexprdata;
13825 
13826  return NULL;
13827 }
13828 
13829 /** @} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
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:782
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4212
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2082
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:4060
SCIP_Longint SCIPgetExprNewSoltag(SCIP *scip)
Definition: scip_expr.c:1641
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
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:1417
SCIP_RETCODE SCIPgetCharParam(SCIP *scip, const char *name, char *value)
Definition: scip_param.c:326
static volatile int nterms
Definition: interrupt.c:47
SCIP_Bool SCIPnlhdlrIsEnabled(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:190
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:500
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:643
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8187
SCIP_EXPR_OWNERDATA * SCIPexprGetOwnerData(SCIP_EXPR *expr)
Definition: expr.c:3862
void SCIPexprSetIntegrality(SCIP_EXPR *expr, SCIP_Bool isintegral)
Definition: expr.c:4030
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
primal heuristic that tries a given solution
SCIP_RETCODE SCIPskipSpace(char **s)
Definition: misc.c:10777
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:110
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:3175
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5203
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:1763
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:66
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:56
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3296
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:91
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:365
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:72
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8349
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip_sol.c:1318
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:191
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:1707
void SCIPsetLPFeastol(SCIP *scip, SCIP_Real newfeastol)
Definition: scip_lp.c:438
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2497
SCIP_RETCODE SCIPaddDialogEntry(SCIP *scip, SCIP_DIALOG *dialog, SCIP_DIALOG *subdialog)
Definition: scip_dialog.c:171
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:354
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:886
#define SCIP_NLHDLR_METHOD_SEPABELOW
Definition: type_nlhdlr.h:51
static SCIP_RETCODE addLocks(SCIP *scip, SCIP_CONS *cons, int nlockspos, int nlocksneg)
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3801
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:126
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:2788
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:50
static SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17901
SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
Definition: lpi_clp.cpp:3692
#define SCIP_MAXSTRLEN
Definition: def.h:302
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:3199
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3354
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip_var.c:8814
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:155
int SCIPnlhdlrGetDetectPriority(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:170
const char * SCIPexprhdlrGetName(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:532
SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1805
#define SCIP_DECL_CONSGETDIVEBDCHGS(x)
Definition: type_cons.h:918
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:2843
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#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:17957
SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1181
SCIP_EXPR * SCIPexpriterSkipDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:929
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18264
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:1029
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:104
SCIP_RETCODE SCIPlpiChgSides(SCIP_LPI *lpi, int nrows, const int *ind, const SCIP_Real *lhs, const SCIP_Real *rhs)
Definition: lpi_clp.cpp:1167
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17351
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
Definition: misc_rowprep.c:792
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1439
#define TABLE_EARLIEST_STAGE_NLHDLR
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1248
SCIP_Real SCIPgetBranchingPoint(SCIP *scip, SCIP_VAR *var, SCIP_Real suggestion)
Definition: scip_branch.c:897
SCIP_TABLE * SCIPfindTable(SCIP *scip, const char *name)
Definition: scip_table.c:94
SCIP_RETCODE SCIPstopClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:178
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:1794
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: scip_var.c:8950
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:1141
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10307
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:610
SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
Definition: scip_expr.c:2336
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:4554
#define FALSE
Definition: def.h:96
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:4645
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3024
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:687
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:10788
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:3352
#define TRUE
Definition: def.h:95
SCIP_RETCODE SCIPgetNlRowNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
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:4317
static SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:54
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3142
SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI *lpi, SCIP_LPPARAM type, SCIP_Real dval)
Definition: lpi_clp.cpp:3833
#define SCIP_DECL_NLHDLRDETECT(x)
Definition: type_nlhdlr.h:177
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:63
void SCIPexpriterSetChildUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition: expriter.c:837
SCIP_Real SCIPgetLPFeastol(SCIP *scip)
Definition: scip_lp.c:428
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:194
int SCIPdialogFindEntry(SCIP_DIALOG *dialog, const char *entryname, SCIP_DIALOG **subdialog)
Definition: dialog.c:1028
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_RETCODE SCIPlpiGetNCols(SCIP_LPI *lpi, int *ncols)
Definition: lpi_clp.cpp:1435
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition: expr.c:3957
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:10294
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5320
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define CONSHDLR_SEPAFREQ
SCIP_SIDETYPE SCIProwprepGetSidetype(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:667
static SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
void SCIPnlhdlrPrintStatistics(SCIP *scip, SCIP_NLHDLR **nlhdlrs, int nnlhdlrs, FILE *file)
Definition: nlhdlr.c:698
int SCIPrandomGetInt(SCIP_RANDNUMGEN *randnumgen, int minrandval, int maxrandval)
Definition: misc.c:10019
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:234
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
Constraint handler for AND constraints, .
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
SCIP_RETCODE SCIPfreeClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:127
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:222
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3211
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:370
SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_var.c:390
static SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
SCIP_Bool SCIPqueueIsEmpty(SCIP_QUEUE *queue)
Definition: misc.c:1184
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:4613
SCIP_EXPRITER_USERDATA SCIPexpriterGetCurrentUserData(SCIP_EXPRITER *iterator)
Definition: expriter.c:755
#define SCIP_NLHDLR_METHOD_ALL
Definition: type_nlhdlr.h:55
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:5989
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
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:2354
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:1116
#define SCIP_EXPRITER_ENTEREXPR
Definition: type_expr.h:676
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8359
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:125
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition: expr.c:4181
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:126
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17312
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
#define SCIPdebugMsgPrint
Definition: scip_message.h:79
#define SCIPdebugMsg
Definition: scip_message.h:78
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:83
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:1079
SCIP_RETCODE SCIPaddLinearCoefToNlRow(SCIP *scip, SCIP_NLROW *nlrow, SCIP_VAR *var, SCIP_Real val)
Definition: scip_nlp.c:1116
SCIP_EXPRCURV SCIPgetCurvatureNonlinear(SCIP_CONS *cons)
SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
Definition: expriter.c:682
SCIP_VAR ** x
Definition: circlepacking.c:63
SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
Definition: lpi_clp.cpp:531
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8151
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18253
SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1657
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:208
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2172
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:943
struct SCIP_Expr_OwnerData SCIP_EXPR_OWNERDATA
Definition: type_expr.h:77
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:2246
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8389
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1625
#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:3373
SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:647
SCIP_Real SCIPgetBranchScore(SCIP *scip, SCIP_VAR *var, SCIP_Real downgain, SCIP_Real upgain)
Definition: scip_branch.c:849
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:252
SCIP_Bool SCIPisLbBetter(SCIP *scip, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7444
void * SCIPgetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx)
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1880
static SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip_var.c:8176
static SCIP_RETCODE createAuxVar(SCIP *scip, SCIP_EXPR *expr)
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3811
SCIP_DIALOG * SCIPgetRootDialog(SCIP *scip)
Definition: scip_dialog.c:157
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17911
SCIP_Bool active
SCIP_VAR * w
Definition: circlepacking.c:67
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:59
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:117
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:144
SCIP_Real inf
Definition: intervalarith.h:55
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:618
static SCIP_DECL_CONSCHECK(consCheckNonlinear)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:612
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:53
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:1868
SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1166
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1450
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition: expr.c:3973
SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:76
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:627
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:258
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition: expr.c:3875
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:64
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4182
#define CONSHDLR_ENFOPRIORITY
static SCIP_DECL_CONSINITLP(consInitlpNonlinear)
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition: expr.c:3901
SCIP_Bool SCIProwprepIsLocal(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:677
#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:363
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:17151
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:315
int SCIPgetExprNEnfosNonlinear(SCIP_EXPR *expr)
const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:150
#define SCIP_DECL_NLHDLREVALAUX(x)
Definition: type_nlhdlr.h:202
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3474
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:652
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition: expr_var.c:416
static SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
SCIP_Bool SCIPnlhdlrHasIntEval(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:210
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1025
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:137
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:483
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
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:8090
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:8715
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1432
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8309
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17242
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:5108
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3058
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4202
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:4105
#define NULL
Definition: lpi_spx1.cpp:164
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:2638
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1491
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:210
SCIP_RETCODE SCIPgetExprVarExprs(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **varexprs, int *nvarexprs)
Definition: scip_expr.c:2070
SCIP_RETCODE SCIPaddExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_Real coef)
SCIP_Real SCIPexprGetBardot(SCIP_EXPR *expr)
Definition: expr.c:3929
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:3944
#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:581
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition: scip_sepa.c:339
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:394
#define SCIPhashTwo(a, b)
Definition: pub_misc.h:519
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:61
int SCIPexpriterGetChildIdxDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:706
SCIP_Real SCIPgetExprPartialDiffGradientDirNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_VAR *var)
#define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
Definition: scip_mem.h:107
int SCIPgetNTotalVars(SCIP *scip)
Definition: scip_prob.c:2569
SCIP_RETCODE SCIPbranchVarVal(SCIP *scip, SCIP_VAR *var, SCIP_Real val, SCIP_NODE **downchild, SCIP_NODE **eqchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1126
SCIP_VAR * h
Definition: circlepacking.c:68
SCIP_Real sup
Definition: intervalarith.h:56
SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_value.c:270
SCIP_Longint SCIPexprGetEvalTag(SCIP_EXPR *expr)
Definition: expr.c:3888
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define consGetDiveBdChgsNonlinear
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8329
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:963
SCIP_VAR ** SCIProwprepGetModifiedVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:707
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:967
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:250
const char * SCIPnlhdlrGetDesc(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:160
#define VERTEXPOLY_USEDUALSIMPLEX
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
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:208
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 SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:123
#define VERTEXPOLY_RANDNUMINITSEED
union SCIP_ConsNonlinear_BilinTerm::@4 aux
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4597
SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2296
#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:697
Ipopt NLP interface.
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1221
#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:1053
#define SCIP_Bool
Definition: def.h:93
#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:629
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:286
static SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:168
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:662
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1030
SCIP_RETCODE SCIPchgNlRowConstant(SCIP *scip, SCIP_NLROW *nlrow, SCIP_Real constant)
Definition: scip_nlp.c:1093
SCIP_CONSNONLINEAR_BILINTERM * SCIPgetBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:3919
static const char * paramname[]
Definition: lpi_msk.c:5096
SCIP_RETCODE SCIPnlhdlrFree(SCIP *scip, SCIP_NLHDLR **nlhdlr)
Definition: nlhdlr.c:363
SCIP_EXPRCURV
Definition: type_expr.h:57
SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2609
SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
Definition: cons.c:8208
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:319
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition: var.c:17547
SCIP_Bool SCIPdialogHasEntry(SCIP_DIALOG *dialog, const char *entryname)
Definition: dialog.c:995
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:670
unsigned int SCIP_NLHDLR_METHOD
Definition: type_nlhdlr.h:57
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:2482
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:92
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:361
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8110
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11932
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:127
#define CONSHDLR_PROPFREQ
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8219
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:2032
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:94
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:320
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:985
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8289
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8259
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17749
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:400
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:4020
SCIP_RETCODE SCIPcomputeExprIntegrality(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1989
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:857
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:665
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:921
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:58
SCIP_EXPR * SCIPexpriterGetChildExprDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:720
#define consDelvarsNonlinear
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:17612
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition: expr.c:3824
Constraint handler for linear constraints in their most general form, .
static SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2220
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2558
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:207
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:726
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2037
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:10041
int SCIPnlhdlrGetEnfoPriority(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:180
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:97
SCIP_CONSHDLR * SCIProwGetOriginConshdlr(SCIP_ROW *row)
Definition: lp.c:17456
constant value expression handler
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2296
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
#define SCIP_REAL_MAX
Definition: def.h:187
#define CONSHDLR_SEPAPRIORITY
SCIP_RETCODE SCIPsetNlRowExpr(SCIP *scip, SCIP_NLROW *nlrow, SCIP_EXPR *expr)
Definition: scip_nlp.c:1203
void SCIPexpriterSetStagesDFS(SCIP_EXPRITER *iterator, SCIP_EXPRITER_STAGE stopstages)
Definition: expriter.c:663
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:391
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2310
static SCIP_DECL_CONSDELETE(consDeleteNonlinear)
void SCIPenableNLP(SCIP *scip)
Definition: scip_nlp.c:95
#define BRANCH_RANDNUMINITSEED
SCIP_Real * r
Definition: circlepacking.c:59
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:8197
int SCIPgetExprNLocksPosNonlinear(SCIP_EXPR *expr)
#define CONSHDLR_PRESOLTIMING
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
#define SCIP_EVENTTYPE_BESTSOLFOUND
Definition: type_event.h:105
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3389
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:4931
#define VERTEXPOLY_MAXPERTURBATION
SCIP_RETCODE SCIPcreatePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
SCIP_DIALOG * SCIPdialoghdlrGetRoot(SCIP_DIALOGHDLR *dialoghdlr)
Definition: dialog.c:436
int SCIPhashmapGetNElements(SCIP_HASHMAP *hashmap)
Definition: misc.c:3483
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:247
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:943
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:167
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:1668
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8120
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:677
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:144
SCIP_Real SCIProwprepGetSide(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:657
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:152
static SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1119
#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:695
void SCIPexpriterSetCurrentUserData(SCIP_EXPRITER *iterator, SCIP_EXPRITER_USERDATA userdata)
Definition: expriter.c:805
#define SCIP_NLHDLR_METHOD_ACTIVITY
Definition: type_nlhdlr.h:54
SCIP_NLHDLR * nlhdlr
SCIP_SOLORIGIN SCIPsolGetOrigin(SCIP_SOL *sol)
Definition: sol.c:2545
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:66
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:4145
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
int SCIPgetNNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17361
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:1214
#define SCIP_Real
Definition: def.h:186
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8339
#define CONSHDLR_EAGERFREQ
static SCIP_DECL_CONSFREE(consFreeNonlinear)
#define EPSROUND(x, eps)
Definition: def.h:221
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:64
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:3983
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:8279
#define SCIP_INVALID
Definition: def.h:206
static SCIP_Real getDualBranchscore(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8269
SCIP_Bool SCIPnlhdlrHasEstimate(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:250
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2212
SCIP_Bool SCIPnlhdlrHasInitSepa(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:226
SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
Definition: expr_value.c:294
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:171
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17581
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1190
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
Definition: type_nlhdlr.h:413
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:298
static SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
#define SCIPisFinite(x)
Definition: pub_misc.h:1901
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17407
void * SCIPqueueRemove(SCIP_QUEUE *queue)
Definition: misc.c:1080
#define VERTEXPOLY_ADJUSTFACETFACTOR
SCIP_RETCODE SCIPreleaseDialog(SCIP *scip, SCIP_DIALOG **dialog)
Definition: scip_dialog.c:124
struct SCIP_NlhdlrData SCIP_NLHDLRDATA
Definition: type_nlhdlr.h:412
SCIP_RETCODE SCIPlpiChgObj(SCIP_LPI *lpi, int ncols, const int *ind, const SCIP_Real *obj)
Definition: lpi_clp.cpp:1240
#define CONSHDLR_MAXPREROUNDS
static SCIP_DECL_CONSPRINT(consPrintNonlinear)
#define SCIP_EXPRITER_LEAVEEXPR
Definition: type_expr.h:679
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:73
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
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:17967
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
Definition: misc_rowprep.c:904
int SCIPgetPtrarrayMinIdx(SCIP *scip, SCIP_PTRARRAY *ptrarray)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
#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:1941
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:677
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:3106
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:132
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:82
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:91
#define CONSHDLR_DESC
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition: expriter.c:968
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:3231
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:1220
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:366
static SCIP_DECL_CONSPARSE(consParseNonlinear)
SCIP_INTERVAL SCIPgetExprBoundsNonlinear(SCIP *scip, SCIP_EXPR *expr)
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition: lp.c:17140
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:17433
SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
#define SCIP_NLHDLR_METHOD_SEPABOTH
Definition: type_nlhdlr.h:53
SCIP_RETCODE SCIPstartClock(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:161
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1361
static SCIP_DECL_SORTINDCOMP(branchcandCompare)
int SCIPexprGetNUses(SCIP_EXPR *expr)
Definition: expr.c:3791
#define SCIP_NLHDLR_METHOD_SEPAABOVE
Definition: type_nlhdlr.h:52
#define SCIPnlhdlrIncrementNSeparated(nlhdlr)
Definition: nlhdlr.h:128
void SCIPnlrowSetCurvature(SCIP_NLROW *nlrow, SCIP_EXPRCURV curvature)
Definition: nlp.c:1842
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1337
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:139
SCIP_Bool SCIPcolIsInLP(SCIP_COL *col)
Definition: lp.c:17115
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:57
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:637
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:151
SCIP_RETCODE SCIPfreePtrarray(SCIP *scip, SCIP_PTRARRAY **ptrarray)
static SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
SCIP_Real domain
#define SCIP_EVENTTYPE_BOUNDRELAXED
Definition: type_event.h:124
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)