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 2002-2022 Zuse Institute Berlin */
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 <assert.h>
56 #include <ctype.h>
57 
58 #include "scip/cons_nonlinear.h"
59 #include "scip/nlhdlr.h"
60 #include "scip/expr_var.h"
61 #include "scip/expr_sum.h"
62 #include "scip/expr_value.h"
63 #include "scip/expr_pow.h"
64 #include "scip/nlhdlr_convex.h"
65 #include "scip/cons_linear.h"
66 #include "scip/cons_varbound.h"
67 #include "scip/cons_and.h"
69 #include "scip/heur_subnlp.h"
70 #include "scip/heur_trysol.h"
71 #include "scip/nlpi_ipopt.h" /* for SCIPsolveLinearEquationsIpopt */
72 #include "scip/debug.h"
73 #include "scip/dialog_default.h"
74 
75 /* fundamental constraint handler properties */
76 #define CONSHDLR_NAME "nonlinear"
77 #define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
78 #define CONSHDLR_ENFOPRIORITY -60 /**< priority of the constraint handler for constraint enforcing */
79 #define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
80 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
81  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
82 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
83 
84 /* optional constraint handler properties */
85 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
86 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
87 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
88 
89 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
90 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
91 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
92 
93 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
94 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
95 
96 /* properties of the nonlinear constraint handler statistics table */
97 #define TABLE_NAME_NONLINEAR "cons_nonlinear"
98 #define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
99 #define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
100 #define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
102 /* properties of the nonlinear handler statistics table */
103 #define TABLE_NAME_NLHDLR "nlhdlr"
104 #define TABLE_DESC_NLHDLR "nonlinear handler statistics"
105 #define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
106 #define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
108 #define DIALOG_NAME "nlhdlrs"
109 #define DIALOG_DESC "display nonlinear handlers"
110 #define DIALOG_ISSUBMENU FALSE
112 #define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
113 #define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
114 #define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
115 #define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
117 #define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
119 #define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
121 /** translate from one value of infinity to another
122  *
123  * if val is &ge; infty1, then give infty2, else give val
124  */
125 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
127 /** translates x to 2^x for non-negative integer x */
128 #define POWEROFTWO(x) (0x1u << (x))
130 #ifdef ENFO_LOGGING
131 #define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
132 FILE* enfologfile = NULL;
133 #else
134 #define ENFOLOG(x)
135 #endif
136 
137 /*
138  * Data structures
139  */
140 
141 /** enforcement data of an expression */
142 typedef struct
143 {
144  SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
145  SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
146  SCIP_NLHDLR_METHOD nlhdlrparticipation; /**< methods where nonlinear handler participates */
147  SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
148  SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
149  SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
150  SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
152 
153 /** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
154 struct SCIP_Expr_OwnerData
155 {
156  SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
157 
158  /* locks and monotonicity */
159  int nlockspos; /**< positive locks counter */
160  int nlocksneg; /**< negative locks counter */
161  SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
162  int monotonicitysize; /**< length of monotonicity array */
163 
164  /* propagation (in addition to activity that is stored in expr) */
165  SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
166  unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
167  SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
168 
169  /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
170  EXPRENFO** enfos; /**< enforcements */
171  int nenfos; /**< number of enforcements, or -1 if not initialized */
172  unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
173  unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
174  unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
175  unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
176  SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
177 
178  /* branching */
179  SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
180  SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
181  int nviolscores; /**< number of violation scores stored for this expression */
182  unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
183 
184  /* additional data for variable expressions (TODO move into sub-struct?) */
185  SCIP_CONS** conss; /**< constraints in which this variable appears */
186  int nconss; /**< current number of constraints in conss */
187  int consssize; /**< length of conss array */
188  SCIP_Bool consssorted; /**< is the array of constraints sorted */
189 
190  int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
191 };
192 
193 /** constraint data for nonlinear constraints */
194 struct SCIP_ConsData
195 {
196  /* data that defines the constraint: expression and sides */
197  SCIP_EXPR* expr; /**< expression that represents this constraint */
198  SCIP_Real lhs; /**< left-hand side */
199  SCIP_Real rhs; /**< right-hand side */
200 
201  /* variables */
202  SCIP_EXPR** varexprs; /**< array containing all variable expressions */
203  int nvarexprs; /**< total number of variable expressions */
204  SCIP_Bool catchedevents; /**< do we catch events on variables? */
205 
206  /* constraint violation */
207  SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
208  SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
209  SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
210  SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
211 
212  /* status flags */
213  unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
214  unsigned int issimplified:1; /**< did we simplify the expression tree already? */
215 
216  /* locks */
217  int nlockspos; /**< number of positive locks */
218  int nlocksneg; /**< number of negative locks */
219 
220  /* repair infeasible solutions */
221  SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
222  SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
223  SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
224  SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
225 
226  /* miscellaneous */
227  SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
228  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
229  int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
230 };
231 
232 /** constraint upgrade method */
233 typedef struct
234 {
235  SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
236  int priority; /**< priority of upgrading method */
237  SCIP_Bool active; /**< is upgrading enabled */
239 
240 /** constraint handler data */
241 struct SCIP_ConshdlrData
242 {
243  /* nonlinear handler */
244  SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
245  int nnlhdlrs; /**< number of nonlinear handlers */
246  int nlhdlrssize; /**< size of nlhdlrs array */
247  SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
248  SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
249  SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
250 
251  /* constraint upgrades */
252  CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
253  int consupgradessize; /**< size of consupgrades array */
254  int nconsupgrades; /**< number of constraint upgrade methods */
255 
256  /* other plugins */
257  SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
258  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
259  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
260 
261  /* tags and counters */
262  int auxvarid; /**< unique id for the next auxiliary variable */
263  SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
264  SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
265  SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
266  unsigned int enforound; /**< total number of enforcement calls, including current one */
267  int lastconsindex; /**< last used consindex, plus one */
268 
269  /* activity intervals and domain propagation */
270  SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
271  SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
272  SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
273  SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
274  unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
275 
276  /* parameters */
277  int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
278  SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
279  char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
280  SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
281  SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
282  SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
283  SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
284  SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
285  SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
286  SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
287  int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
288  SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
289  SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
290  SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
291  SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
292  SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
293  SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
294  SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
295  SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
296  SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
297  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 */
298  char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
299  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) */
300  int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
301  SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
302  SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
303  SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
304  SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
305  SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
306  SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
307  SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
308  SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
309  char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
310  char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
311  SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
312  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) */
313  SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
314 
315  /* statistics */
316  SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
317  SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
318  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 */
319  SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
320  SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
321  SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
322  SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
323  SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
324 
325  /* facets of envelops of vertex-polyhedral functions */
326  SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
327  SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
328 
329  /* hashing of bilinear terms */
330  SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
331  SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
332  int nbilinterms; /**< total number of bilinear terms */
333  int bilintermssize; /**< size of bilinterms array */
334  int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
335 
336  /* branching */
337  SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
338  char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
339 
340  /* misc */
341  SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
342  SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
343  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
344 };
345 
346 /** branching candidate with various scores */
347 typedef struct
348 {
349  SCIP_EXPR* expr; /**< expression that holds branching candidate */
350  SCIP_Real auxviol; /**< aux-violation score of candidate */
351  SCIP_Real domain; /**< domain score of candidate */
352  SCIP_Real dual; /**< dual score of candidate */
353  SCIP_Real pscost; /**< pseudo-cost score of candidate */
354  SCIP_Real vartype; /**< variable type score of candidate */
355  SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
357 
358 /*
359  * Local methods
360  */
361 
362 /* forward declaration */
363 static
365  SCIP* scip, /**< SCIP data structure */
366  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
367  SCIP_EXPR* rootexpr, /**< expression */
368  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
369  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
370  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
371  );
372 
373 /** frees auxiliary variables of expression, if any */
374 static
376  SCIP* scip, /**< SCIP data structure */
377  SCIP_EXPR* expr /**< expression which auxvar to free, if any */
378  )
379 {
380  SCIP_EXPR_OWNERDATA* mydata;
381 
382  assert(scip != NULL);
383  assert(expr != NULL);
384 
385  mydata = SCIPexprGetOwnerData(expr);
386  assert(mydata != NULL);
387 
388  if( mydata->auxvar == NULL )
389  return SCIP_OKAY;
390 
391  SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
392 
393  /* remove variable locks
394  * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
395  */
396  SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
397 
398  /* release auxiliary variable */
399  SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
400  assert(mydata->auxvar == NULL);
401 
402  return SCIP_OKAY;
403 }
404 
405 /** frees data used for enforcement of expression, that is, nonlinear handlers
406  *
407  * can also clear indicators whether expr needs enforcement methods, that is,
408  * free an associated auxiliary variable and reset the nactivityuses counts
409  */
410 static
412  SCIP* scip, /**< SCIP data structure */
413  SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
414  SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
415  )
416 {
417  SCIP_EXPR_OWNERDATA* mydata;
418  int e;
419 
420  mydata = SCIPexprGetOwnerData(expr);
421  assert(mydata != NULL);
422 
423  if( freeauxvar )
424  {
425  /* free auxiliary variable */
426  SCIP_CALL( freeAuxVar(scip, expr) );
427  assert(mydata->auxvar == NULL);
428 
429  /* reset count on activity and auxvar usage */
430  mydata->nactivityusesprop = 0;
431  mydata->nactivityusessepa = 0;
432  mydata->nauxvaruses = 0;
433  }
434 
435  /* free data stored by nonlinear handlers */
436  for( e = 0; e < mydata->nenfos; ++e )
437  {
438  SCIP_NLHDLR* nlhdlr;
439 
440  assert(mydata->enfos[e] != NULL);
441 
442  nlhdlr = mydata->enfos[e]->nlhdlr;
443  assert(nlhdlr != NULL);
444 
445  if( mydata->enfos[e]->issepainit )
446  {
447  /* call the separation deinitialization callback of the nonlinear handler */
448  SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
449  mydata->enfos[e]->issepainit = FALSE;
450  }
451 
452  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
453  if( mydata->enfos[e]->nlhdlrexprdata != NULL )
454  {
455  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
456  assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
457  }
458 
459  /* free enfo data */
460  SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
461  }
462 
463  /* free array with enfo data */
464  SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
465 
466  /* we need to look at this expression in detect again */
467  mydata->nenfos = -1;
468 
469  return SCIP_OKAY;
470 }
471 
472 /** callback that frees data that this conshdlr stored in an expression */
473 static
474 SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
475 {
476  assert(scip != NULL);
477  assert(expr != NULL);
478  assert(ownerdata != NULL);
479  assert(*ownerdata != NULL);
480 
481  /* expression should not be locked anymore */
482  assert((*ownerdata)->nlockspos == 0);
483  assert((*ownerdata)->nlocksneg == 0);
484 
485  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
486 
487  /* expression should not be enforced anymore */
488  assert((*ownerdata)->nenfos <= 0);
489  assert((*ownerdata)->auxvar == NULL);
490 
491  if( SCIPisExprVar(scip, expr) )
492  {
493  SCIP_CONSHDLRDATA* conshdlrdata;
494  SCIP_VAR* var;
495 
496  /* there should be no constraints left that still use this variable */
497  assert((*ownerdata)->nconss == 0);
498  /* thus, there should also be no variable event catched (via this exprhdlr) */
499  assert((*ownerdata)->filterpos == -1);
500 
501  SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
502 
503  /* update var2expr hashmap in conshdlrdata */
504  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
505  assert(conshdlrdata != NULL);
506 
507  var = SCIPgetVarExprVar(expr);
508  assert(var != NULL);
509 
510  /* remove var -> expr map from hashmap if present
511  * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
512  * if variable-expression stored for var is different, then also do nothing)
513  */
514  if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
515  {
516  SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
517  }
518  }
519 
520  SCIPfreeBlockMemory(scip, ownerdata);
521 
522  return SCIP_OKAY;
523 }
524 
525 static
526 SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
527 { /*lint --e{715}*/
528  assert(ownerdata != NULL);
529 
530  /* print nl handlers associated to expr */
531  if( ownerdata->nenfos > 0 )
532  {
533  int i;
534  SCIPinfoMessage(scip, file, " {");
535 
536  for( i = 0; i < ownerdata->nenfos; ++i )
537  {
538  SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
539  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
540  SCIPinfoMessage(scip, file, "a");
541  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
542  SCIPinfoMessage(scip, file, "u");
543  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
544  SCIPinfoMessage(scip, file, "o");
545  if( i < ownerdata->nenfos-1 )
546  SCIPinfoMessage(scip, file, ", ");
547  }
548 
549  SCIPinfoMessage(scip, file, "}");
550  }
551 
552  /* print aux var associated to expr */
553  if( ownerdata->auxvar != NULL )
554  {
555  SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
556  }
557  SCIPinfoMessage(scip, file, "\n");
558 
559  return SCIP_OKAY;
560 }
561 
562 /** possibly reevaluates and then returns the activity of the expression
563  *
564  * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
565  */
566 static
567 SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
568 {
569  SCIP_CONSHDLRDATA* conshdlrdata;
570 
571  assert(scip != NULL);
572  assert(expr != NULL);
573  assert(ownerdata != NULL);
574 
575  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
576  assert(conshdlrdata != NULL);
577 
578  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
579  {
580  /* update activity of expression */
581  SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
582 
583  assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
584  }
585 
586  return SCIP_OKAY;
587 }
588 
589 /** callback that creates data that this conshdlr wants to store in an expression */
590 static
591 SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
592 {
593  assert(scip != NULL);
594  assert(expr != NULL);
595  assert(ownerdata != NULL);
596 
597  SCIP_CALL( SCIPallocClearBlockMemory(scip, ownerdata) );
598  (*ownerdata)->nenfos = -1;
599  (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
600 
601  if( SCIPisExprVar(scip, expr) )
602  {
603  SCIP_CONSHDLRDATA* conshdlrdata;
604  SCIP_VAR* var;
605 
606  (*ownerdata)->filterpos = -1;
607 
608  /* add to var2expr hashmap if not having expr for var yet */
609 
610  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
611  assert(conshdlrdata != NULL);
612 
613  var = SCIPgetVarExprVar(expr);
614 
615  if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
616  {
617  /* store the variable expression in the hashmap */
618  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
619  }
620  else
621  {
622  /* if expr was just created, then it shouldn't already be stored as image of var */
623  assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
624  }
625  }
626  else
627  {
628  /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
629  (*ownerdata)->filterpos = -2;
630  }
631 
632  *ownerfree = exprownerFree;
633  *ownerprint = exprownerPrint;
634  *ownerevalactivity = exprownerEvalactivity;
635 
636  return SCIP_OKAY;
637 }
638 
639 /** creates a variable expression or retrieves from hashmap in conshdlr data */
640 static
642  SCIP* scip, /**< SCIP data structure */
643  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
644  SCIP_EXPR** expr, /**< pointer where to store expression */
645  SCIP_VAR* var /**< variable to be stored */
646  )
647 {
648  assert(conshdlr != NULL);
649  assert(expr != NULL);
650  assert(var != NULL);
651 
652  /* get variable expression representing the given variable if there is one already */
653  *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
654 
655  if( *expr == NULL )
656  {
657  /* create a new variable expression; this also captures the expression */
658  SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
659  assert(*expr != NULL);
660  /* exprownerCreate should have added var->expr to var2expr */
661  assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
662  }
663  else
664  {
665  /* only capture already existing expr to get a consistent uses-count */
666  SCIPcaptureExpr(*expr);
667  }
668 
669  return SCIP_OKAY;
670 }
671 
672 /* map var exprs to var-expr from var2expr hashmap */
673 static
674 SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
675 { /*lint --e{715}*/
676  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
677 
678  assert(sourcescip != NULL);
679  assert(targetscip != NULL);
680  assert(sourceexpr != NULL);
681  assert(targetexpr != NULL);
682  assert(*targetexpr == NULL);
683  assert(mapexprdata != NULL);
684 
685  /* do not provide map if not variable */
686  if( !SCIPisExprVar(sourcescip, sourceexpr) )
687  return SCIP_OKAY;
688 
689  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
690 
691  return SCIP_OKAY;
692 }
693 
694 /* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
695 static
696 SCIP_DECL_EXPR_MAPEXPR(mapexprtransvar)
697 { /*lint --e{715}*/
698  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
699  SCIP_VAR* var;
700 
701  assert(sourcescip != NULL);
702  assert(targetscip != NULL);
703  assert(sourceexpr != NULL);
704  assert(targetexpr != NULL);
705  assert(*targetexpr == NULL);
706  assert(mapexprdata != NULL);
707 
708  /* do not provide map if not variable */
709  if( !SCIPisExprVar(sourcescip, sourceexpr) )
710  return SCIP_OKAY;
711 
712  var = SCIPgetVarExprVar(sourceexpr);
713  assert(var != NULL);
714 
715  /* transform variable */
716  SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
717  assert(var != NULL);
718 
719  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
720 
721  return SCIP_OKAY;
722 }
723 
724 /** stores all variable expressions into a given constraint */
725 static
727  SCIP* scip, /**< SCIP data structure */
728  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
729  SCIP_CONSDATA* consdata /**< constraint data */
730  )
731 {
732  SCIP_CONSHDLRDATA* conshdlrdata;
733  int varexprssize;
734  int i;
735 
736  assert(consdata != NULL);
737 
738  /* skip if we have stored the variable expressions already */
739  if( consdata->varexprs != NULL )
740  return SCIP_OKAY;
741 
742  assert(consdata->varexprs == NULL);
743  assert(consdata->nvarexprs == 0);
744 
745  /* get an upper bound on number of variable expressions */
746  if( consdata->issimplified )
747  {
748  /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
749  * so we cannot have more variable expression than the number of active variables
750  */
751  varexprssize = SCIPgetNVars(scip);
752  }
753  else
754  {
755  SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
756  }
757 
758  /* create array to store all variable expressions */
759  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
760 
761  SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
762  assert(varexprssize >= consdata->nvarexprs);
763 
764  /* shrink array if there are less variables in the expression than in the problem */
765  if( varexprssize > consdata->nvarexprs )
766  {
767  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
768  }
769 
770  conshdlrdata = SCIPconshdlrGetData(conshdlr);
771  assert(conshdlrdata != NULL);
772  assert(conshdlrdata->var2expr != NULL);
773 
774  /* ensure that for every variable an entry exists in the var2expr hashmap
775  * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
776  */
777  for( i = 0; i < consdata->nvarexprs; ++i )
778  {
779  if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
780  {
781  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
782  }
783  }
784 
785  return SCIP_OKAY;
786 }
787 
788 /** frees all variable expression stored in storeVarExprs() */
789 static
791  SCIP* scip, /**< SCIP data structure */
792  SCIP_CONSDATA* consdata /**< constraint data */
793  )
794 {
795  int i;
796 
797  assert(consdata != NULL);
798 
799  /* skip if we have stored the variable expressions already*/
800  if( consdata->varexprs == NULL )
801  return SCIP_OKAY;
802 
803  assert(consdata->varexprs != NULL);
804  assert(consdata->nvarexprs >= 0);
805 
806  /* release variable expressions */
807  for( i = 0; i < consdata->nvarexprs; ++i )
808  {
809  assert(consdata->varexprs[i] != NULL);
810  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
811  assert(consdata->varexprs[i] == NULL);
812  }
813 
814  /* free variable expressions */
815  SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
816  consdata->varexprs = NULL;
817  consdata->nvarexprs = 0;
818 
819  return SCIP_OKAY;
820 }
821 
822 /** interval evaluation of variables as used in bound tightening
823  *
824  * Returns slightly relaxed local variable bounds of a variable as interval.
825  * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
826  */
827 static
828 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
829 {
830  SCIP_INTERVAL interval;
831  SCIP_CONSHDLRDATA* conshdlrdata;
832  SCIP_Real lb;
833  SCIP_Real ub;
834 
835  assert(scip != NULL);
836  assert(var != NULL);
837 
838  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
839  assert(conshdlrdata != NULL);
840 
841  if( conshdlrdata->globalbounds )
842  {
843  lb = SCIPvarGetLbGlobal(var);
844  ub = SCIPvarGetUbGlobal(var);
845  }
846  else
847  {
848  lb = SCIPvarGetLbLocal(var);
849  ub = SCIPvarGetUbLocal(var);
850  }
851  assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
852 
853  /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
855  {
856  lb = EPSROUND(lb, 0.0); /*lint !e835*/
857  ub = EPSROUND(ub, 0.0); /*lint !e835*/
858  }
859 
860  /* integer variables should always have integral bounds in SCIP */
861  assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
862  assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
863 
864  switch( conshdlrdata->varboundrelax )
865  {
866  case 'n' : /* no relaxation */
867  break;
868 
869  case 'a' : /* relax by absolute value */
870  {
871  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
872  if( SCIPvarIsIntegral(var) )
873  break;
874 
875  if( !SCIPisInfinity(scip, -lb) )
876  {
877  /* reduce lb by epsilon, or to the next integer value, which ever is larger */
878  SCIP_Real bnd = floor(lb);
879  lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
880  }
881 
882  if( !SCIPisInfinity(scip, ub) )
883  {
884  /* increase ub by epsilon, or to the next integer value, which ever is smaller */
885  SCIP_Real bnd = ceil(ub);
886  ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
887  }
888 
889  break;
890  }
891 
892  case 'b' : /* relax always by absolute value */
893  {
894  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
895  if( SCIPvarIsIntegral(var) )
896  break;
897 
898  if( !SCIPisInfinity(scip, -lb) )
899  lb -= conshdlrdata->varboundrelaxamount;
900 
901  if( !SCIPisInfinity(scip, ub) )
902  ub += conshdlrdata->varboundrelaxamount;
903 
904  break;
905  }
906 
907  case 'r' : /* relax by relative value */
908  {
909  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
910  if( SCIPvarIsIntegral(var) )
911  break;
912 
913  /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
914  * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
915  * further, do not relax beyond next integer value
916  */
917  if( !SCIPisInfinity(scip, -lb) )
918  {
919  SCIP_Real bnd = floor(lb);
920  lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
921  }
922 
923  if( !SCIPisInfinity(scip, ub) )
924  {
925  SCIP_Real bnd = ceil(ub);
926  ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
927  }
928 
929  break;
930  }
931 
932  default :
933  {
934  SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
935  SCIPABORT();
936  break;
937  }
938  }
939 
940  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
943  assert(lb <= ub);
944 
945  SCIPintervalSetBounds(&interval, lb, ub);
946 
947  return interval;
948 }
949 
950 /** compares two nonlinear constraints by its index
951  *
952  * Usable as compare operator in array sort functions.
953  */
954 static
955 SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
956 {
957  SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
958  SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
959 
960  assert(consdata1 != NULL);
961  assert(consdata2 != NULL);
962 
963  return consdata1->consindex - consdata2->consindex;
964 }
965 
966 /** processes variable fixing or bound change event */
967 static
968 SCIP_DECL_EVENTEXEC(processVarEvent)
969 { /*lint --e{715}*/
970  SCIP_EVENTTYPE eventtype;
971  SCIP_EXPR* expr;
972  SCIP_EXPR_OWNERDATA* ownerdata;
973 
974  eventtype = SCIPeventGetType(event);
976 
977  assert(eventdata != NULL);
978  expr = (SCIP_EXPR*) eventdata;
979  assert(SCIPisExprVar(scip, expr));
980 
981  SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
985 
986  ownerdata = SCIPexprGetOwnerData(expr);
987  assert(ownerdata != NULL);
988  /* we only catch varevents for variables in constraints, so there should be constraints */
989  assert(ownerdata->nconss > 0);
990  assert(ownerdata->conss != NULL);
991 
992  /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
993  * - propagation can only find something new if a bound was tightened
994  * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
995  * and we look at global changes (that is, we are not looking at boundchanges in probing)
996  */
998  {
999  SCIP_CONSDATA* consdata;
1000  int c;
1001 
1002  for( c = 0; c < ownerdata->nconss; ++c )
1003  {
1004  assert(ownerdata->conss[c] != NULL);
1005  consdata = SCIPconsGetData(ownerdata->conss[c]);
1006 
1007  /* if bound tightening, then mark constraints to be propagated again
1008  * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1009  * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1010  * the locks don't help since they are not available separately for each constraint
1011  */
1012  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1013  {
1014  consdata->ispropagated = FALSE;
1015  SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1016  }
1017 
1018  /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1019  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !SCIPinProbing(scip) )
1020  {
1021  consdata->issimplified = FALSE;
1022  SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1023  }
1024  }
1025  }
1026 
1027  /* update curboundstag, lastboundrelax, and expr activity */
1028  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1029  {
1030  SCIP_CONSHDLRDATA* conshdlrdata;
1031  SCIP_INTERVAL activity;
1032 
1033  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1034  assert(conshdlrdata != NULL);
1035 
1036  /* increase tag on bounds */
1037  ++conshdlrdata->curboundstag;
1038  assert(conshdlrdata->curboundstag > 0);
1039 
1040  /* remember also if we relaxed bounds now */
1041  if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1042  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1043 
1044  /* update the activity of the var-expr here immediately
1045  * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1046  */
1047  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1048  /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1049 #ifdef DEBUG_PROP
1050  SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1051 #endif
1052  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1053  }
1054 
1055  return SCIP_OKAY;
1056 }
1057 
1058 /** registers event handler to catch variable events on variable
1059  *
1060  * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1061  * When an event occurs, all stored constraints are notified.
1062  */
1063 static
1065  SCIP* scip, /**< SCIP data structure */
1066  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1067  SCIP_EXPR* expr, /**< variable expression */
1068  SCIP_CONS* cons /**< nonlinear constraint */
1069  )
1070 {
1071  SCIP_EXPR_OWNERDATA* ownerdata;
1072 
1073  assert(eventhdlr != NULL);
1074  assert(expr != NULL);
1075  assert(SCIPisExprVar(scip, expr));
1076  assert(cons != NULL);
1077 
1078  ownerdata = SCIPexprGetOwnerData(expr);
1079  assert(ownerdata != NULL);
1080 
1081 #ifndef NDEBUG
1082  /* assert that constraint does not double-catch variable */
1083  {
1084  int i;
1085  for( i = 0; i < ownerdata->nconss; ++i )
1086  assert(ownerdata->conss[i] != cons);
1087  }
1088 #endif
1089 
1090  /* append cons to ownerdata->conss */
1091  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1092  ownerdata->conss[ownerdata->nconss++] = cons;
1093  /* we're not capturing the constraint here to avoid circular references */
1094 
1095  /* updated sorted flag */
1096  if( ownerdata->nconss <= 1 )
1097  ownerdata->consssorted = TRUE;
1098  else if( ownerdata->consssorted )
1099  ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1100 
1101  /* catch variable events, if not done so yet (first constraint) */
1102  if( ownerdata->filterpos < 0 )
1103  {
1104  SCIP_EVENTTYPE eventtype;
1105 
1106  assert(ownerdata->nconss == 1);
1107 
1109 
1110  SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1111  assert(ownerdata->filterpos >= 0);
1112  }
1113 
1114  return SCIP_OKAY;
1115 }
1116 
1117 /** catch variable events */
1118 static
1120  SCIP* scip, /**< SCIP data structure */
1121  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1122  SCIP_CONS* cons /**< constraint for which to catch bound change events */
1123  )
1124 {
1125  SCIP_CONSHDLRDATA* conshdlrdata;
1126  SCIP_CONSDATA* consdata;
1127  SCIP_EXPR* expr;
1128  int i;
1129 
1130  assert(eventhdlr != NULL);
1131  assert(cons != NULL);
1132 
1133  consdata = SCIPconsGetData(cons);
1134  assert(consdata != NULL);
1135  assert(consdata->varexprs != NULL);
1136  assert(consdata->nvarexprs >= 0);
1137 
1138  /* check if we have catched variable events already */
1139  if( consdata->catchedevents )
1140  return SCIP_OKAY;
1141 
1142  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1143  assert(conshdlrdata != NULL);
1144  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1145 
1146  SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1147 
1148  for( i = 0; i < consdata->nvarexprs; ++i )
1149  {
1150  expr = consdata->varexprs[i];
1151 
1152  assert(expr != NULL);
1153  assert(SCIPisExprVar(scip, expr));
1154 
1155  SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1156 
1157  /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1158  * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1159  */
1160  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1161  {
1162  SCIP_INTERVAL activity;
1163  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1164  /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1165  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1166 #ifdef DEBUG_PROP
1167  SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1168 #endif
1169  }
1170  }
1171 
1172  consdata->catchedevents = TRUE;
1173 
1174  return SCIP_OKAY;
1175 }
1176 
1177 /** unregisters event handler to catch variable events on variable
1178  *
1179  * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1180  * If this was the last constraint, then the event handler is unregistered for this variable.
1181  */
1182 static
1184  SCIP* scip, /**< SCIP data structure */
1185  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1186  SCIP_EXPR* expr, /**< variable expression */
1187  SCIP_CONS* cons /**< expr constraint */
1188  )
1189 {
1190  SCIP_EXPR_OWNERDATA* ownerdata;
1191  int pos;
1192 
1193  assert(eventhdlr != NULL);
1194  assert(expr != NULL);
1195  assert(SCIPisExprVar(scip, expr));
1196  assert(cons != NULL);
1197 
1198  ownerdata = SCIPexprGetOwnerData(expr);
1199  assert(ownerdata != NULL);
1200  assert(ownerdata->nconss > 0);
1201 
1202  if( ownerdata->conss[ownerdata->nconss-1] == cons )
1203  {
1204  pos = ownerdata->nconss-1;
1205  }
1206  else
1207  {
1208  if( !ownerdata->consssorted )
1209  {
1210  SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1211  ownerdata->consssorted = TRUE;
1212  }
1213 
1214  if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1215  {
1216  SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1217  return SCIP_ERROR;
1218  }
1219  assert(pos >= 0 && pos < ownerdata->nconss);
1220  }
1221  assert(ownerdata->conss[pos] == cons);
1222 
1223  /* move last constraint into position of removed constraint */
1224  if( pos < ownerdata->nconss-1 )
1225  {
1226  ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1227  ownerdata->consssorted = FALSE;
1228  }
1229  --ownerdata->nconss;
1230 
1231  /* drop variable events if that was the last constraint */
1232  if( ownerdata->nconss == 0 )
1233  {
1234  SCIP_EVENTTYPE eventtype;
1235 
1236  assert(ownerdata->filterpos >= 0);
1237 
1239 
1240  SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1241  ownerdata->filterpos = -1;
1242  }
1243 
1244  return SCIP_OKAY;
1245 }
1246 
1247 /** drop variable events */
1248 static
1250  SCIP* scip, /**< SCIP data structure */
1251  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1252  SCIP_CONS* cons /**< constraint for which to drop bound change events */
1253  )
1254 {
1255  SCIP_CONSDATA* consdata;
1256  int i;
1257 
1258  assert(eventhdlr != NULL);
1259  assert(cons != NULL);
1260 
1261  consdata = SCIPconsGetData(cons);
1262  assert(consdata != NULL);
1263 
1264  /* check if we have catched variable events already */
1265  if( !consdata->catchedevents )
1266  return SCIP_OKAY;
1267 
1268  assert(consdata->varexprs != NULL);
1269  assert(consdata->nvarexprs >= 0);
1270 
1271  SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1272 
1273  for( i = consdata->nvarexprs - 1; i >= 0; --i )
1274  {
1275  assert(consdata->varexprs[i] != NULL);
1276 
1277  SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1278  }
1279 
1280  consdata->catchedevents = FALSE;
1281 
1282  return SCIP_OKAY;
1283 }
1284 
1285 /** creates and captures a nonlinear constraint
1286  *
1287  * @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
1288  */
1289 static
1291  SCIP* scip, /**< SCIP data structure */
1292  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1293  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1294  const char* name, /**< name of constraint */
1295  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1296  SCIP_Real lhs, /**< left hand side of constraint */
1297  SCIP_Real rhs, /**< right hand side of constraint */
1298  SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1299  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1300  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1301  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1302  * Usually set to TRUE. */
1303  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1304  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1305  SCIP_Bool check, /**< should the constraint be checked for feasibility?
1306  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1307  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1308  * Usually set to TRUE. */
1309  SCIP_Bool local, /**< is constraint only valid locally?
1310  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1311  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1312  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1313  * adds coefficients to this constraint. */
1314  SCIP_Bool dynamic, /**< is constraint subject to aging?
1315  * Usually set to FALSE. Set to TRUE for own cuts which
1316  * are separated as constraints. */
1317  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1318  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1319  )
1320 {
1321  SCIP_CONSHDLRDATA* conshdlrdata;
1322  SCIP_CONSDATA* consdata;
1323 
1324  assert(conshdlr != NULL);
1325  assert(expr != NULL);
1326 
1327  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1328  assert(conshdlrdata != NULL);
1329 
1330  if( local && SCIPgetDepth(scip) != 0 )
1331  {
1332  SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1333  return SCIP_INVALIDCALL;
1334  }
1335 
1336  /* TODO we should allow for non-initial nonlinear constraints */
1337  if( !initial )
1338  {
1339  SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1340  return SCIP_INVALIDCALL;
1341  }
1342 
1343  /* create constraint data */
1344  SCIP_CALL( SCIPallocClearBlockMemory(scip, &consdata) );
1345 
1346  if( copyexpr )
1347  {
1348  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1349  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1350  }
1351  else
1352  {
1353  consdata->expr = expr;
1354  SCIPcaptureExpr(consdata->expr);
1355  }
1356  consdata->lhs = lhs;
1357  consdata->rhs = rhs;
1358  consdata->consindex = conshdlrdata->lastconsindex++;
1359  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1360 
1361  /* create constraint */
1362  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1363  local, modifiable, dynamic, removable, FALSE) );
1364 
1365  return SCIP_OKAY;
1366 }
1367 
1368 /** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1369  *
1370  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1371  * Assume that f(x) is associated with auxiliary variable z.
1372  *
1373  * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1374  * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1375  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1376  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1377  *
1378  * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1379  */
1380 static
1382  SCIP* scip, /**< SCIP data structure */
1383  SCIP_EXPR* expr, /**< expression */
1384  SCIP_SOL* sol, /**< solution that has been evaluated */
1385  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1386  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1387  )
1388 {
1389  SCIP_EXPR_OWNERDATA* ownerdata;
1390  SCIP_Real auxvarvalue;
1391 
1392  assert(expr != NULL);
1393 
1394  ownerdata = SCIPexprGetOwnerData(expr);
1395  assert(ownerdata != NULL);
1396  assert(ownerdata->auxvar != NULL);
1397 
1398  if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1399  {
1400  if( violunder != NULL )
1401  *violunder = TRUE;
1402  if( violover != NULL )
1403  *violover = TRUE;
1404  return SCIPinfinity(scip);
1405  }
1406 
1407  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1408 
1409  if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1410  {
1411  if( violunder != NULL )
1412  *violunder = FALSE;
1413  if( violover != NULL )
1414  *violover = TRUE;
1415  return auxvarvalue - SCIPexprGetEvalValue(expr);
1416  }
1417 
1418  if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1419  {
1420  if( violunder != NULL )
1421  *violunder = TRUE;
1422  if( violover != NULL )
1423  *violover = FALSE;
1424  return SCIPexprGetEvalValue(expr) - auxvarvalue;
1425  }
1426 
1427  if( violunder != NULL )
1428  *violunder = FALSE;
1429  if( violover != NULL )
1430  *violover = FALSE;
1431  return 0.0;
1432 }
1433 
1434 /** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1435  *
1436  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1437  * Assume that f(w) is associated with auxiliary variable z.
1438  *
1439  * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1440  * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1441  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1442  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1443  *
1444  * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1445  */
1446 static
1448  SCIP* scip, /**< SCIP data structure */
1449  SCIP_EXPR* expr, /**< expression */
1450  SCIP_Real auxvalue, /**< value of f(w) */
1451  SCIP_SOL* sol, /**< solution that has been evaluated */
1452  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1453  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1454  )
1455 {
1456  SCIP_EXPR_OWNERDATA* ownerdata;
1457  SCIP_Real auxvarvalue;
1458 
1459  assert(expr != NULL);
1460 
1461  ownerdata = SCIPexprGetOwnerData(expr);
1462  assert(ownerdata != NULL);
1463  assert(ownerdata->auxvar != NULL);
1464 
1465  if( auxvalue == SCIP_INVALID )
1466  {
1467  if( violunder != NULL )
1468  *violunder = TRUE;
1469  if( violover != NULL )
1470  *violover = TRUE;
1471  return SCIPinfinity(scip);
1472  }
1473 
1474  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1475 
1476  if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1477  {
1478  if( violunder != NULL )
1479  *violunder = FALSE;
1480  if( violover != NULL )
1481  *violover = TRUE;
1482  return auxvarvalue - auxvalue;
1483  }
1484 
1485  if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1486  {
1487  if( violunder != NULL )
1488  *violunder = TRUE;
1489  if( violover != NULL )
1490  *violover = FALSE;
1491  return auxvalue - auxvarvalue;
1492  }
1493 
1494  if( violunder != NULL )
1495  *violunder = FALSE;
1496  if( violover != NULL )
1497  *violover = FALSE;
1498 
1499  return 0.0;
1500 }
1501 
1502 /** computes violation of a constraint */
1503 static
1505  SCIP* scip, /**< SCIP data structure */
1506  SCIP_CONS* cons, /**< constraint */
1507  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1508  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1509  )
1510 {
1511  SCIP_CONSDATA* consdata;
1512  SCIP_Real activity;
1513 
1514  assert(scip != NULL);
1515  assert(cons != NULL);
1516 
1517  consdata = SCIPconsGetData(cons);
1518  assert(consdata != NULL);
1519 
1520  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1521  activity = SCIPexprGetEvalValue(consdata->expr);
1522 
1523  /* consider constraint as violated if it is undefined in the current point */
1524  if( activity == SCIP_INVALID )
1525  {
1526  consdata->lhsviol = SCIPinfinity(scip);
1527  consdata->rhsviol = SCIPinfinity(scip);
1528  return SCIP_OKAY;
1529  }
1530 
1531  /* compute violations */
1532  consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1533  consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1534 
1535  return SCIP_OKAY;
1536 }
1537 
1538 /** returns absolute violation of a constraint
1539  *
1540  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1541  */
1542 static
1544  SCIP_CONS* cons /**< constraint */
1545  )
1546 {
1547  SCIP_CONSDATA* consdata;
1548 
1549  assert(cons != NULL);
1550 
1551  consdata = SCIPconsGetData(cons);
1552  assert(consdata != NULL);
1553 
1554  return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1555 }
1556 
1557 /** computes relative violation of a constraint
1558  *
1559  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1560  */
1561 static
1563  SCIP* scip, /**< SCIP data structure */
1564  SCIP_CONS* cons, /**< constraint */
1565  SCIP_Real* viol, /**< buffer to store violation */
1566  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1567  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1568  )
1569 {
1570  SCIP_CONSHDLR* conshdlr;
1571  SCIP_CONSHDLRDATA* conshdlrdata;
1572  SCIP_CONSDATA* consdata;
1573  SCIP_Real scale;
1574 
1575  assert(cons != NULL);
1576  assert(viol != NULL);
1577 
1578  conshdlr = SCIPconsGetHdlr(cons);
1579  assert(conshdlr != NULL);
1580 
1581  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1582  assert(conshdlrdata != NULL);
1583 
1584  *viol = getConsAbsViolation(cons);
1585 
1586  if( conshdlrdata->violscale == 'n' )
1587  return SCIP_OKAY;
1588 
1589  if( SCIPisInfinity(scip, *viol) )
1590  return SCIP_OKAY;
1591 
1592  consdata = SCIPconsGetData(cons);
1593  assert(consdata != NULL);
1594 
1595  if( conshdlrdata->violscale == 'a' )
1596  {
1597  scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1598 
1599  /* consider value of side that is violated for scaling, too */
1600  if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1601  {
1602  assert(!SCIPisInfinity(scip, -consdata->lhs));
1603  scale = REALABS(consdata->lhs);
1604  }
1605  else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1606  {
1607  assert(!SCIPisInfinity(scip, consdata->rhs));
1608  scale = REALABS(consdata->rhs);
1609  }
1610 
1611  *viol /= scale;
1612  return SCIP_OKAY;
1613  }
1614 
1615  /* if not 'n' or 'a', then it has to be 'g' at the moment */
1616  assert(conshdlrdata->violscale == 'g');
1617  if( soltag == 0L || consdata->gradnormsoltag != soltag )
1618  {
1619  /* we need the varexprs to conveniently access the gradient */
1620  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1621 
1622  /* update cached value of norm of gradient */
1623  consdata->gradnorm = 0.0;
1624 
1625  /* compute gradient */
1626  SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1627 
1628  /* gradient evaluation error -> no scaling */
1629  if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1630  {
1631  int i;
1632  for( i = 0; i < consdata->nvarexprs; ++i )
1633  {
1634  SCIP_Real deriv;
1635 
1636  assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1637  deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1638  if( deriv == SCIP_INVALID )
1639  {
1640  /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1641  consdata->gradnorm = 0.0;
1642  break;
1643  }
1644 
1645  consdata->gradnorm += deriv*deriv;
1646  }
1647  }
1648  consdata->gradnorm = sqrt(consdata->gradnorm);
1649  consdata->gradnormsoltag = soltag;
1650  }
1651 
1652  *viol /= MAX(1.0, consdata->gradnorm);
1653 
1654  return SCIP_OKAY;
1655 }
1656 
1657 /** returns whether constraint is currently violated
1658  *
1659  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1660  */
1661 static
1663  SCIP* scip, /**< SCIP data structure */
1664  SCIP_CONS* cons /**< constraint */
1665  )
1666 {
1667  return getConsAbsViolation(cons) > SCIPfeastol(scip);
1668 }
1669 
1670 /** checks for a linear variable that can be increased or decreased without harming feasibility */
1671 static
1673  SCIP* scip, /**< SCIP data structure */
1674  SCIP_CONS* cons /**< constraint */
1675  )
1676 {
1677  SCIP_CONSDATA* consdata;
1678  int poslock;
1679  int neglock;
1680  int i;
1681 
1682  assert(cons != NULL);
1683 
1684  consdata = SCIPconsGetData(cons);
1685  assert(consdata != NULL);
1686 
1687  consdata->linvarincr = NULL;
1688  consdata->linvardecr = NULL;
1689  consdata->linvarincrcoef = 0.0;
1690  consdata->linvardecrcoef = 0.0;
1691 
1692  /* root expression is not a sum -> no unlocked linear variable available */
1693  if( !SCIPisExprSum(scip, consdata->expr) )
1694  return;
1695 
1696  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1697  {
1698  SCIP_EXPR* child;
1699 
1700  child = SCIPexprGetChildren(consdata->expr)[i];
1701  assert(child != NULL);
1702 
1703  /* check whether the child is a variable expression */
1704  if( SCIPisExprVar(scip, child) )
1705  {
1706  SCIP_VAR* var = SCIPgetVarExprVar(child);
1707  SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1708 
1709  if( coef > 0.0 )
1710  {
1711  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1712  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1713  }
1714  else
1715  {
1716  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1717  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1718  }
1720 
1721  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1722  {
1723  /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1724  * if we have already one candidate, then take the one where the loss in the objective function is less
1725  */
1726  if( (consdata->linvardecr == NULL) ||
1727  (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1728  {
1729  consdata->linvardecr = var;
1730  consdata->linvardecrcoef = coef;
1731  }
1732  }
1733 
1734  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1735  {
1736  /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1737  * if we have already one candidate, then take the one where the loss in the objective function is less
1738  */
1739  if( (consdata->linvarincr == NULL) ||
1740  (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1741  {
1742  consdata->linvarincr = var;
1743  consdata->linvarincrcoef = coef;
1744  }
1745  }
1746  }
1747  }
1748 
1749  assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1750  assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1751 
1752  if( consdata->linvarincr != NULL )
1753  {
1754  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1755  }
1756  if( consdata->linvardecr != NULL )
1757  {
1758  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1759  }
1760 }
1761 
1762 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1763  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1764  *
1765  * The method assumes that this is always possible and that not all constraints are feasible already.
1766  */
1767 static
1769  SCIP* scip, /**< SCIP data structure */
1770  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1771  SCIP_CONS** conss, /**< constraints to process */
1772  int nconss, /**< number of constraints */
1773  SCIP_SOL* sol, /**< solution to process */
1774  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1775  )
1776 {
1777  SCIP_CONSHDLRDATA* conshdlrdata;
1778  SCIP_SOL* newsol;
1779  int c;
1780 
1781  assert(scip != NULL);
1782  assert(conshdlr != NULL);
1783  assert(conss != NULL || nconss == 0);
1784  assert(success != NULL);
1785 
1786  *success = FALSE;
1787 
1788  /* don't propose new solutions if not in presolve or solving */
1790  return SCIP_OKAY;
1791 
1792  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1793  assert(conshdlrdata != NULL);
1794 
1795  if( sol != NULL )
1796  {
1797  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1798  }
1799  else
1800  {
1801  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1802  }
1803  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1804  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1805  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1806 
1807  for( c = 0; c < nconss; ++c )
1808  {
1809  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1810  SCIP_Real viol = 0.0;
1811  SCIP_Real delta;
1812  SCIP_Real gap;
1813 
1814  assert(consdata != NULL);
1815 
1816  /* get absolute violation and sign */
1817  if( consdata->lhsviol > SCIPfeastol(scip) )
1818  viol = consdata->lhsviol; /* lhs - activity */
1819  else if( consdata->rhsviol > SCIPfeastol(scip) )
1820  viol = -consdata->rhsviol; /* rhs - activity */
1821  else
1822  continue; /* constraint is satisfied */
1823 
1824  if( consdata->linvarincr != NULL &&
1825  ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1826  {
1827  SCIP_VAR* var = consdata->linvarincr;
1828 
1829  /* compute how much we would like to increase var */
1830  delta = viol / consdata->linvarincrcoef;
1831  assert(delta > 0.0);
1832 
1833  /* if var has an upper bound, may need to reduce delta */
1834  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1835  {
1836  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1837  delta = MIN(MAX(0.0, gap), delta);
1838  }
1839  if( SCIPisPositive(scip, delta) )
1840  {
1841  /* if variable is integral, round delta up so that it will still have an integer value */
1842  if( SCIPvarIsIntegral(var) )
1843  delta = SCIPceil(scip, delta);
1844 
1845  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1846  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1847  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1848 
1849  /* adjust constraint violation, if satisfied go on to next constraint */
1850  viol -= consdata->linvarincrcoef * delta;
1851  if( SCIPisZero(scip, viol) )
1852  continue;
1853  }
1854  }
1855 
1856  assert(viol != 0.0);
1857  if( consdata->linvardecr != NULL &&
1858  ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1859  {
1860  SCIP_VAR* var = consdata->linvardecr;
1861 
1862  /* compute how much we would like to decrease var */
1863  delta = viol / consdata->linvardecrcoef;
1864  assert(delta < 0.0);
1865 
1866  /* if var has a lower bound, may need to reduce delta */
1867  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
1868  {
1869  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1870  delta = MAX(MIN(0.0, gap), delta);
1871  }
1872  if( SCIPisNegative(scip, delta) )
1873  {
1874  /* if variable is integral, round delta down so that it will still have an integer value */
1875  if( SCIPvarIsIntegral(var) )
1876  delta = SCIPfloor(scip, delta);
1877  SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1878  /*lint --e{613} */
1879  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1880  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1881 
1882  /* adjust constraint violation, if satisfied go on to next constraint */
1883  viol -= consdata->linvardecrcoef * delta;
1884  if( SCIPisZero(scip, viol) )
1885  continue;
1886  }
1887  }
1888 
1889  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1890  break;
1891  }
1892 
1893  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1894  * then pass it to the trysol heuristic
1895  */
1896  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1897  {
1898  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1899 
1900  assert(conshdlrdata->trysolheur != NULL);
1901  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1902 
1903  *success = TRUE;
1904  }
1905 
1906  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1907 
1908  return SCIP_OKAY;
1909 }
1910 
1911 /** adds globally valid tight estimators in a given solution as cut to cutpool
1912  *
1913  * Called by addTightEstimatorCuts() for a specific expression, nlhdlr, and estimate-direction (over or under).
1914  */
1915 static
1917  SCIP* scip, /**< SCIP data structure */
1918  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1919  SCIP_CONS* cons, /**< constraint */
1920  SCIP_EXPR* expr, /**< expression */
1921  EXPRENFO* exprenfo, /**< expression enfo data, e.g., nlhdlr to use */
1922  SCIP_SOL* sol, /**< reference point where to estimate */
1923  SCIP_Bool overestimate, /**< whether to overestimate */
1924  SCIP_PTRARRAY* rowpreps /**< array for rowpreps */
1925  )
1926 {
1927  SCIP_Bool estimatesuccess = FALSE;
1928  SCIP_Bool branchscoresuccess = FALSE;
1929  int minidx;
1930  int maxidx;
1931  int r;
1932 
1933  assert(scip != NULL);
1934  assert(expr != NULL);
1935  assert(exprenfo != NULL);
1936  assert(rowpreps != NULL);
1937 
1938  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %sestimate using nlhdlr <%s> for expr %p (%s)\n",
1939  overestimate ? "over" : "under", SCIPnlhdlrGetName(exprenfo->nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))); )
1940 
1941  SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, exprenfo->nlhdlr, expr, exprenfo->nlhdlrexprdata, sol,
1942  exprenfo->auxvalue, overestimate, overestimate ? SCIPinfinity(scip) : -SCIPinfinity(scip), FALSE, rowpreps, &estimatesuccess, &branchscoresuccess) );
1943 
1944  minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
1945  maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
1946  assert(estimatesuccess == (minidx <= maxidx));
1947 
1948  if( !estimatesuccess )
1949  {
1950  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n", SCIPnlhdlrGetName(exprenfo->nlhdlr)); )
1951  return SCIP_OKAY;
1952  }
1953 
1954  for( r = minidx; r <= maxidx; ++r )
1955  {
1956  SCIP_ROWPREP* rowprep;
1957  SCIP_ROW* row;
1958  SCIP_Real estimateval;
1959  int i;
1960 
1961  rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
1962  assert(rowprep != NULL);
1963  assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
1964 
1965  /* if estimators is only local valid, then skip */
1966  if( SCIProwprepIsLocal(rowprep) )
1967  {
1968  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip local estimator\n"); )
1969  SCIPfreeRowprep(scip, &rowprep);
1970  continue;
1971  }
1972 
1973  /* compute value of estimator */
1974  estimateval = -SCIProwprepGetSide(rowprep);
1975  for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
1976  estimateval += SCIProwprepGetCoefs(rowprep)[i] * SCIPgetSolVal(scip, sol, SCIProwprepGetVars(rowprep)[i]);
1977 
1978  /* if estimator value is not tight (or even "more than tight", e.g., when estimating in integer vars), then skip */
1979  if( (overestimate && !SCIPisFeasLE(scip, estimateval, SCIPexprGetEvalValue(expr))) ||
1980  (!overestimate && !SCIPisFeasGE(scip, estimateval, SCIPexprGetEvalValue(expr))) )
1981  {
1982  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip non-tight estimator with value %g, expr value %g\n", estimateval, SCIPexprGetEvalValue(expr)); )
1983  SCIPfreeRowprep(scip, &rowprep);
1984  continue;
1985  }
1986 
1987  /* complete estimator to cut and clean it up */
1988  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
1989  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPinfinity(scip), &estimatesuccess) );
1990 
1991  /* if cleanup failed or rowprep is local now, then skip */
1992  if( !estimatesuccess || SCIProwprepIsLocal(rowprep) )
1993  {
1994  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip after cleanup failed or made estimator locally valid\n"); )
1995  SCIPfreeRowprep(scip, &rowprep);
1996  continue;
1997  }
1998 
1999  /* generate row and add to cutpool */
2000  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
2001 
2002  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
2003  SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
2004 
2005  SCIP_CALL( SCIPaddPoolCut(scip, row) );
2006  /* SCIPnlhdlrIncrementNSeparated(nlhdlr); */
2007 
2008  SCIP_CALL( SCIPreleaseRow(scip, &row) );
2009  SCIPfreeRowprep(scip, &rowprep);
2010  }
2011 
2012  SCIP_CALL( SCIPclearPtrarray(scip, rowpreps) );
2013 
2014  return SCIP_OKAY;
2015 }
2016 
2017 /** adds globally valid tight estimators in a given solution as cuts to cutpool
2018  *
2019  * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
2020  * For convex constraints, we would achieve this by linearizing.
2021  * To avoid checking explicitly for convexity, we compute estimators via any nlhdlr that didn't say it would
2022  * use bound information and check whether the estimator is tight.
2023  *
2024  * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
2025  * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
2026  */
2027 static
2029  SCIP* scip, /**< SCIP data structure */
2030  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2031  SCIP_CONS** conss, /**< constraints */
2032  int nconss, /**< number of constraints */
2033  SCIP_SOL* sol /**< reference point where to estimate */
2034  )
2035 {
2036  SCIP_CONSDATA* consdata;
2037  SCIP_Longint soltag;
2038  SCIP_EXPRITER* it;
2039  SCIP_EXPR* expr;
2040  SCIP_PTRARRAY* rowpreps;
2041  int c, e;
2042 
2043  assert(scip != NULL);
2044  assert(conshdlr != NULL);
2045  assert(conss != NULL || nconss == 0);
2046 
2047  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "add tight estimators in new solution from <%s> to cutpool\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
2048 
2049  /* TODO probably we just evaluated all expressions when checking the sol before it was added
2050  * would be nice to recognize this and skip reevaluating
2051  */
2052  soltag = SCIPgetExprNewSoltag(scip);
2053 
2054  SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
2055 
2056  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2059 
2060  for( c = 0; c < nconss; ++c )
2061  {
2062  /* skip constraints that are not enabled or deleted or have separation disabled */
2063  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2064  continue;
2065  assert(SCIPconsIsActive(conss[c]));
2066 
2067  consdata = SCIPconsGetData(conss[c]);
2068  assert(consdata != NULL);
2069 
2070  /* TODO we could remember for which constraints there is a chance that we would add anything,
2071  * i.e., there is some convex-like expression, and skip other constraints
2072  */
2073 
2074  ENFOLOG(
2075  {
2076  int i;
2077  SCIPinfoMessage(scip, enfologfile, " constraint ");
2078  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2079  SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2080  for( i = 0; i < consdata->nvarexprs; ++i )
2081  {
2082  SCIP_VAR* var;
2083  var = SCIPgetVarExprVar(consdata->varexprs[i]);
2084  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2085  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2086  }
2087  })
2088 
2089  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2090  assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2091 
2092  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2093  {
2094  SCIP_EXPR_OWNERDATA* ownerdata;
2095 
2096  ownerdata = SCIPexprGetOwnerData(expr);
2097  assert(ownerdata != NULL);
2098 
2099  /* we can only generate a cut from an estimator if there is an auxvar */
2100  if( ownerdata->auxvar == NULL )
2101  continue;
2102 
2103  /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2104  assert(SCIPexprGetEvalTag(expr) == soltag);
2105  assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2106  SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2107 
2108  /* generate cuts from estimators of each nonlinear handler that provides estimates */
2109  for( e = 0; e < ownerdata->nenfos; ++e )
2110  {
2111  SCIP_NLHDLR* nlhdlr;
2112 
2113  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2114  assert(nlhdlr != NULL);
2115 
2116  /* skip nlhdlr that does not implement estimate (so it does enfo) */
2117  if( !SCIPnlhdlrHasEstimate(nlhdlr) )
2118  continue;
2119 
2120  /* skip nlhdlr that does not participate in separation or looks like it would give only locally-valid estimators
2121  * (because it uses activities on vars/auxvars)
2122  */
2123  if( ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 || ownerdata->enfos[e]->sepaaboveusesactivity) &&
2124  ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 || ownerdata->enfos[e]->sepabelowusesactivity) )
2125  continue;
2126 
2127  /* skip nlhdlr_default on sum, as the estimator doesn't depend on the reference point (expr is linear in auxvars) */
2128  if( SCIPisExprSum(scip, expr) && strcmp(SCIPnlhdlrGetName(nlhdlr), "default") == 0 )
2129  continue;
2130 
2131  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables, since some nlhdlr expect this before their estimate is called */
2132  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
2133  ENFOLOG(
2134  SCIPinfoMessage(scip, enfologfile, " expr ");
2135  SCIPprintExpr(scip, expr, enfologfile);
2136  SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g, nlhdlr <%s> auxvalue: %.15g\n",
2137  (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar), SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
2138  )
2139  /* due to setting values of auxvars to expr values in sol, the auxvalue should equal to expr evalvalue */
2140  assert(SCIPisEQ(scip, ownerdata->enfos[e]->auxvalue, SCIPexprGetEvalValue(expr)));
2141 
2142  /* if nlhdlr wants to be called for overestimate and does not use local bounds, then call estimate of nlhdlr */
2143  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) && !ownerdata->enfos[e]->sepaaboveusesactivity )
2144  {
2145  SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, TRUE, rowpreps) );
2146  }
2147 
2148  /* if nlhdlr wants to be called for underestimate and does not use local bounds, then call estimate of nlhdlr */
2149  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) && !ownerdata->enfos[e]->sepabelowusesactivity )
2150  {
2151  SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, FALSE, rowpreps) );
2152  }
2153  }
2154  }
2155  }
2156 
2157  SCIPfreeExpriter(&it);
2158  SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
2159 
2160  return SCIP_OKAY;
2161 }
2162 
2163 /** processes the event that a new primal solution has been found */
2164 static
2165 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2167  SCIP_CONSHDLR* conshdlr;
2168  SCIP_CONSHDLRDATA* conshdlrdata;
2169  SCIP_SOL* sol;
2170 
2171  assert(scip != NULL);
2172  assert(event != NULL);
2173  assert(eventdata != NULL);
2174  assert(eventhdlr != NULL);
2175  assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND);
2176 
2177  conshdlr = (SCIP_CONSHDLR*)eventdata;
2178 
2179  if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2180  return SCIP_OKAY;
2181 
2182  sol = SCIPeventGetSol(event);
2183  assert(sol != NULL);
2184 
2185  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2186  assert(conshdlrdata != NULL);
2187 
2188  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2189  * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2190  * from the tree, but postprocessed via proposeFeasibleSolution
2191  */
2192  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2193  return SCIP_OKAY;
2194 
2195  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2196 
2197  SCIP_CALL( addTightEstimatorCuts(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol) );
2198 
2199  return SCIP_OKAY;
2200 }
2201 
2202 /** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2203  *
2204  * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2205  * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2206  *
2207  * Nothing will happen if SCIP is not in presolve or solve.
2208  */
2209 static
2211  SCIP* scip, /**< SCIP data structure */
2212  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2213  SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2214  SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2215  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2216  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2217  )
2218 {
2219  SCIP_VAR* var;
2220  SCIP_Bool tightenedlb;
2221  SCIP_Bool tightenedub;
2222  SCIP_Bool force;
2223 
2224  assert(scip != NULL);
2225  assert(conshdlr != NULL);
2226  assert(expr != NULL);
2227  assert(cutoff != NULL);
2228 
2229  /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2230  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, bounds));
2231 
2232  *cutoff = FALSE;
2233 
2234  /* do not tighten variable in problem stage (important for unittests)
2235  * TODO put some kind of #ifdef UNITTEST around this
2236  */
2238  return SCIP_OKAY;
2239 
2240  var = SCIPgetExprAuxVarNonlinear(expr);
2241  if( var == NULL )
2242  return SCIP_OKAY;
2243 
2244  /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2245  force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2246 
2247  /* try to tighten lower bound of (auxiliary) variable */
2248  SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2249  if( tightenedlb )
2250  {
2251  if( ntightenings != NULL )
2252  ++*ntightenings;
2253  SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2254  }
2255  if( *cutoff )
2256  {
2257  SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2258  return SCIP_OKAY;
2259  }
2260 
2261  /* try to tighten upper bound of (auxiliary) variable */
2262  SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2263  if( tightenedub )
2264  {
2265  if( ntightenings != NULL )
2266  ++*ntightenings;
2267  SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2268  }
2269  if( *cutoff )
2270  {
2271  SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2272  return SCIP_OKAY;
2273  }
2274 
2275  /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2276  * that seems unnecessary and we could easily undo this here, e.g.,
2277  * if( tightenedlb ) expr->activity.inf = bounds.inf
2278  */
2279 
2280  return SCIP_OKAY;
2281 }
2282 
2283 /** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2284  * and tries to tighten the bounds of the auxiliary variables accordingly
2285  */
2286 static
2288  SCIP* scip, /**< SCIP data structure */
2289  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2290  SCIP_EXPR* rootexpr, /**< expression */
2291  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2292  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2293  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2294  )
2295 {
2296  SCIP_EXPRITER* it;
2297  SCIP_EXPR* expr;
2298  SCIP_EXPR_OWNERDATA* ownerdata;
2299  SCIP_CONSHDLRDATA* conshdlrdata;
2300 
2301  assert(scip != NULL);
2302  assert(rootexpr != NULL);
2303 
2304  if( infeasible != NULL )
2305  *infeasible = FALSE;
2306  if( ntightenings != NULL )
2307  *ntightenings = 0;
2308 
2309  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2310  assert(conshdlrdata != NULL);
2311 
2312  /* if value is valid and empty, then we cannot improve, so do nothing */
2313  if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2314  {
2315  SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2316 
2317  if( infeasible != NULL )
2318  *infeasible = TRUE;
2319 
2320  /* just update tag to curboundstag */
2321  SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2322 
2323  return SCIP_OKAY;
2324  }
2325 
2326  /* if value is up-to-date, then nothing to do */
2327  if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2328  {
2329  SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2330 
2331  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2332 
2333  return SCIP_OKAY;
2334  }
2335 
2336  ownerdata = SCIPexprGetOwnerData(rootexpr);
2337  assert(ownerdata != NULL);
2338 
2339  /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2340  * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2341  * during detect, we are in some in-between state where we may want to eval activity
2342  * on exprs that we did not notify about their activity usage
2343  */
2344  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2345  {
2346 #ifdef DEBUG_PROP
2347  SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2348 #endif
2349  SCIPABORT();
2350  return SCIP_OKAY;
2351  }
2352 
2353  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2354  SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2356 
2357  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2358  {
2359  switch( SCIPexpriterGetStageDFS(it) )
2360  {
2362  {
2363  /* skip child if it has been evaluated already */
2364  SCIP_EXPR* child;
2365 
2366  child = SCIPexpriterGetChildExprDFS(it);
2367  if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2368  {
2369  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2370  *infeasible = TRUE;
2371 
2372  expr = SCIPexpriterSkipDFS(it);
2373  continue;
2374  }
2375 
2376  break;
2377  }
2378 
2380  {
2381  SCIP_INTERVAL activity;
2382 
2383  /* we should not have entered this expression if its activity was already up to date */
2384  assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2385 
2386  ownerdata = SCIPexprGetOwnerData(expr);
2387  assert(ownerdata != NULL);
2388 
2389  /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2390  * so we can assume that the activity is up to date for all these variables
2391  * UNLESS we changed the method used to evaluate activity of variable expressions
2392  * or we currently use global bounds (varevents are catched for local bound changes only)
2393  */
2394  if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2395  SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2396  {
2397 #ifndef NDEBUG
2398  SCIP_INTERVAL exprhdlrinterval;
2399 
2400  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2401  assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2402  assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2403 #endif
2404 #ifdef DEBUG_PROP
2405  SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2406 #endif
2407  SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2408 
2409  break;
2410  }
2411 
2412  if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2413  {
2414  /* start with entire activity if current one is invalid */
2416  }
2418  {
2419  /* If already empty, then don't try to compute even better activity.
2420  * If cons_nonlinear were alone, then we should have noted that we are infeasible
2421  * so an assert(infeasible == NULL || *infeasible) should work here.
2422  * However, after reporting a cutoff due to expr->activity being empty,
2423  * SCIP may wander to a different node and call propagation again.
2424  * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2425  * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2426  * we will still have expr->activity being empty, but will have forgotten
2427  * that we found infeasibility here before (!2221#note_134120).
2428  * Therefore we just set *infeasibility=TRUE here and stop.
2429  */
2430  if( infeasible != NULL )
2431  *infeasible = TRUE;
2432  SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2433  break;
2434  }
2435  else
2436  {
2437  /* start with current activity, since it is valid */
2438  activity = SCIPexprGetActivity(expr);
2439  }
2440 
2441  /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2442  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2443  {
2444 #ifdef DEBUG_PROP
2445  SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2446 #endif
2447  break;
2448  }
2449 
2450 #ifdef DEBUG_PROP
2451  SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2452  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2453  SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2454 #endif
2455 
2456  /* run interval eval of nonlinear handlers or expression handler */
2457  if( ownerdata->nenfos > 0 )
2458  {
2459  SCIP_NLHDLR* nlhdlr;
2460  SCIP_INTERVAL nlhdlrinterval;
2461  int e;
2462 
2463  /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2464  for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2465  {
2466  /* skip nlhdlr if it does not want to participate in activity computation */
2467  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2468  continue;
2469 
2470  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2471  assert(nlhdlr != NULL);
2472 
2473  /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2474  if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2475  continue;
2476 
2477  /* let nlhdlr evaluate current expression */
2478  nlhdlrinterval = activity;
2479  SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2480  &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2481 #ifdef DEBUG_PROP
2482  SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2483 #endif
2484 
2485  /* update activity by intersecting with computed activity */
2486  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2487 #ifdef DEBUG_PROP
2488  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2489 #endif
2490  }
2491  }
2492  else
2493  {
2494  /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2495  SCIP_INTERVAL exprhdlrinterval = activity;
2496  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2497 #ifdef DEBUG_PROP
2498  SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2499 #endif
2500 
2501  /* update expr->activity by intersecting with computed activity */
2502  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2503 #ifdef DEBUG_PROP
2504  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2505 #endif
2506  }
2507 
2508  /* if expression is integral, then we try to tighten the interval bounds a bit
2509  * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2510  * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2511  * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2512  * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2513  * (constants should be ok, too)
2514  */
2515  if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2516  {
2517  if( activity.inf > -SCIP_INTERVAL_INFINITY )
2518  activity.inf = SCIPceil(scip, activity.inf);
2519  if( activity.sup < SCIP_INTERVAL_INFINITY )
2520  activity.sup = SCIPfloor(scip, activity.sup);
2521 #ifdef DEBUG_PROP
2522  SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2523 #endif
2524  }
2525 
2526  /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2527  * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2528  */
2529  if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2530  {
2531  SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2532  SCIPintervalSetEmpty(&activity);
2533  }
2534 
2535  /* now finally store activity in expr */
2536  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2537 
2539  {
2540  if( infeasible != NULL )
2541  *infeasible = TRUE;
2542  }
2543  else if( tightenauxvars && ownerdata->auxvar != NULL )
2544  {
2545  SCIP_Bool tighteninfeasible;
2546 
2547  SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2548  if( tighteninfeasible )
2549  {
2550  if( infeasible != NULL )
2551  *infeasible = TRUE;
2552  SCIPintervalSetEmpty(&activity);
2553  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2554  }
2555  }
2556 
2557  break;
2558  }
2559 
2560  default:
2561  /* you should never be here */
2562  SCIPerrorMessage("unexpected iterator stage\n");
2563  SCIPABORT();
2564  break;
2565  }
2566 
2567  expr = SCIPexpriterGetNext(it);
2568  }
2569 
2570  SCIPfreeExpriter(&it);
2571 
2572  return SCIP_OKAY;
2573 }
2574 
2575 /** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2576  *
2577  * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2578  *
2579  * If `subsetsufficient` is FALSE, then we require
2580  * - a change from an unbounded interval to a bounded one, or
2581  * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2582  * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2583  */
2584 static
2586  SCIP* scip, /**< SCIP data structure */
2587  SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2588  SCIP_INTERVAL newinterval, /**< new interval */
2589  SCIP_INTERVAL oldinterval /**< old interval */
2590  )
2591 {
2592  assert(scip != NULL);
2593  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2594  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2595 
2596  if( subsetsufficient )
2597  /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2598  return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2599 
2600  /* check whether lower bound of interval becomes finite */
2601  if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2602  return TRUE;
2603 
2604  /* check whether upper bound of interval becomes finite */
2605  if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2606  return TRUE;
2607 
2608  /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2609  if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2610  return TRUE;
2611 
2612  /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2613  if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2614  return TRUE;
2615 
2616  /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2617  if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2618  return TRUE;
2619 
2620  return FALSE;
2621 }
2622 
2623 /** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2624  *
2625  * The expression will be traversed in breadth first search by using this queue.
2626  *
2627  * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2628  * forwardPropExpr() before calling this function.
2629  *
2630  * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2631  */
2632 static
2634  SCIP* scip, /**< SCIP data structure */
2635  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2636  SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2637  int* ntightenings /**< buffer to store the number of (variable) tightenings */
2638  )
2639 {
2640  SCIP_CONSHDLRDATA* conshdlrdata;
2641  SCIP_EXPR* expr;
2642  SCIP_EXPR_OWNERDATA* ownerdata;
2643 
2644  assert(infeasible != NULL);
2645  assert(ntightenings != NULL);
2646 
2647  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2648  assert(conshdlrdata != NULL);
2649 
2650  *ntightenings = 0;
2651 
2652  /* main loop that calls reverse propagation for expressions on the queue
2653  * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2654  */
2655  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2656  {
2657  SCIP_INTERVAL propbounds;
2658  int e;
2659 
2660  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2661  assert(expr != NULL);
2662 
2663  ownerdata = SCIPexprGetOwnerData(expr);
2664  assert(ownerdata != NULL);
2665 
2666  assert(ownerdata->inpropqueue);
2667  /* mark that the expression is not in the queue anymore */
2668  ownerdata->inpropqueue = FALSE;
2669 
2670  /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2671  * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2672  */
2673  assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2674  assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2675  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2676 
2677  /* this intersects propbounds with activity and auxvar bounds
2678  * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2679  * auxvar bounds separately, so disabling this for now
2680  */
2681 #ifdef SCIP_DISABLED_CODE
2682  propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2683  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, propbounds) )
2684  {
2685  *infeasible = TRUE;
2686  break;
2687  }
2688 #else
2689  propbounds = ownerdata->propbounds;
2690 #endif
2691 
2692  if( ownerdata->nenfos > 0 )
2693  {
2694  /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2695  for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2696  {
2697  SCIP_NLHDLR* nlhdlr;
2698  int nreds;
2699 
2700  /* skip nlhdlr if it does not want to participate in activity computation */
2701  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2702  continue;
2703 
2704  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2705  assert(nlhdlr != NULL);
2706 
2707  /* call the reverseprop of the nlhdlr */
2708 #ifdef SCIP_DEBUG
2709  SCIPdebugMsg(scip, "call reverse propagation for ");
2710  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2711  SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2712 #endif
2713 
2714  nreds = 0;
2715  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2716  assert(nreds >= 0);
2717  *ntightenings += nreds;
2718  }
2719  }
2721  {
2722  /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2723  SCIP_INTERVAL* childrenbounds;
2724  int c;
2725 
2726 #ifdef SCIP_DEBUG
2727  SCIPdebugMsg(scip, "call reverse propagation for ");
2728  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2729  SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2730 #endif
2731 
2732  /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2733  * been initialized in detectNlhdlr yet (nenfos < 0)
2734  */
2735  assert(ownerdata->nenfos < 0);
2736 
2737  SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2738  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2739  childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2740 
2741  /* call the reverseprop of the exprhdlr */
2742  SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2743 
2744  if( !*infeasible )
2745  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2746  {
2747  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2748  }
2749 
2750  SCIPfreeBufferArray(scip, &childrenbounds);
2751  }
2752  }
2753 
2754  /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2755  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2756  {
2757  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2758  assert(expr != NULL);
2759 
2760  ownerdata = SCIPexprGetOwnerData(expr);
2761  assert(ownerdata != NULL);
2762 
2763  /* mark that the expression is not in the queue anymore */
2764  ownerdata->inpropqueue = FALSE;
2765  }
2766 
2767  return SCIP_OKAY;
2768 }
2769 
2770 /** calls domain propagation for a given set of constraints
2771  *
2772  * The algorithm alternates calls of forward and reverse propagation.
2773  * Forward propagation ensures that activity of expressions is up to date.
2774  * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2775  * [lhs,rhs] interval as starting point.
2776  *
2777  * The propagation algorithm works as follows:
2778  * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2779  * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2780  * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2781  * provide tighter bounds
2782  * 3. apply reverse propagation to all collected expressions; don't explore
2783  * sub-expressions which have not changed since the beginning of the propagation loop
2784  * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2785  *
2786  * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2787  * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2788  * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2789  *
2790  * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2791  * e.g., try less to propagate on convex constraints?
2792  */
2793 static
2795  SCIP* scip, /**< SCIP data structure */
2796  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2797  SCIP_CONS** conss, /**< constraints to propagate */
2798  int nconss, /**< total number of constraints */
2799  SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2800  SCIP_RESULT* result, /**< pointer to store the result */
2801  int* nchgbds /**< buffer to add the number of changed bounds */
2802  )
2803 {
2804  SCIP_CONSHDLRDATA* conshdlrdata;
2805  SCIP_CONSDATA* consdata;
2806  SCIP_EXPR_OWNERDATA* ownerdata;
2807  SCIP_Bool cutoff = FALSE;
2808  SCIP_INTERVAL conssides;
2809  int ntightenings;
2810  int roundnr;
2811  SCIP_EXPRITER* revpropcollectit = NULL;
2812  int i;
2813 
2814  assert(scip != NULL);
2815  assert(conshdlr != NULL);
2816  assert(conss != NULL);
2817  assert(nconss >= 0);
2818  assert(result != NULL);
2819  assert(nchgbds != NULL);
2820  assert(*nchgbds >= 0);
2821 
2822  /* no constraints to propagate */
2823  if( nconss == 0 )
2824  {
2825  *result = SCIP_DIDNOTRUN;
2826  return SCIP_OKAY;
2827  }
2828 
2829  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2830  assert(conshdlrdata != NULL);
2831  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2832  assert(!conshdlrdata->globalbounds);
2833 
2834  *result = SCIP_DIDNOTFIND;
2835  roundnr = 0;
2836 
2837  /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2838  conshdlrdata->forceboundtightening = force;
2839 
2840  /* invalidate all propbounds (probably not needed) */
2841  ++conshdlrdata->curpropboundstag;
2842 
2843  /* create iterator that we will use if we need to look at all auxvars */
2844  if( conshdlrdata->propauxvars )
2845  {
2846  SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2847  }
2848 
2849  /* main propagation loop */
2850  do
2851  {
2852  SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2853 
2854  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2855 
2856  /* apply forward propagation (update expression activities)
2857  * and add promising root expressions into queue for reversepropagation
2858  */
2859  for( i = 0; i < nconss; ++i )
2860  {
2861  consdata = SCIPconsGetData(conss[i]);
2862  assert(consdata != NULL);
2863 
2864  /* skip deleted, non-active, or propagation-disabled constraints */
2865  if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2866  continue;
2867 
2868  /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2869  * activity didn't change
2870  */
2871  if( consdata->ispropagated )
2872  continue;
2873 
2874  /* update activities in expression */
2875  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2876  SCIPdebugPrintCons(scip, conss[i], NULL);
2877 
2878  ntightenings = 0;
2879  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2880  assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2881 
2882  if( cutoff )
2883  {
2884  SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2885  *result = SCIP_CUTOFF;
2886  break;
2887  }
2888 
2889  ownerdata = SCIPexprGetOwnerData(consdata->expr);
2890 
2891  /* 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 */
2892  if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2893  {
2894  /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2895  * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2896  * so taking auxvar bounds is enough)
2897  */
2898  if( ownerdata->auxvar == NULL )
2899  {
2900  /* relax sides by SCIPepsilon() and handle infinite sides */
2901  SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2902  SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2903  SCIPintervalSetBounds(&conssides, lhs, rhs);
2904  }
2905  else
2906  {
2907  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2908  }
2909  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2910  }
2911  else
2912  {
2913  /* check whether bounds of any auxvar used in constraint provides a tightening
2914  * (for the root expression, bounds of auxvar are initially set to constraint sides)
2915  * but skip exprs that have an auxvar, but do not participate in propagation
2916  */
2917  SCIP_EXPR* expr;
2918 
2919  assert(revpropcollectit != NULL);
2920  SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2921  for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2922  {
2923  ownerdata = SCIPexprGetOwnerData(expr);
2924  assert(ownerdata != NULL);
2925 
2926  if( ownerdata->auxvar == NULL )
2927  continue;
2928 
2929  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2930  continue;
2931 
2932  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2933  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2934  }
2935  }
2936 
2937  if( cutoff )
2938  {
2939  SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2940  *result = SCIP_CUTOFF;
2941  break;
2942  }
2943 
2944  assert(ntightenings >= 0);
2945  if( ntightenings > 0 )
2946  {
2947  *nchgbds += ntightenings;
2948  *result = SCIP_REDUCEDDOM;
2949  }
2950 
2951  /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2952  consdata->ispropagated = TRUE;
2953  }
2954 
2955  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2956  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2957  assert(ntightenings >= 0);
2958  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2959 
2960  if( cutoff )
2961  {
2962  SCIPdebugMsg(scip, " -> cutoff\n");
2963  *result = SCIP_CUTOFF;
2964  break;
2965  }
2966 
2967  if( ntightenings > 0 )
2968  {
2969  *nchgbds += ntightenings;
2970  *result = SCIP_REDUCEDDOM;
2971  }
2972  }
2973  while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2974 
2975  if( conshdlrdata->propauxvars )
2976  {
2977  SCIPfreeExpriter(&revpropcollectit);
2978  }
2979 
2980  conshdlrdata->forceboundtightening = FALSE;
2981 
2982  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2983  ++conshdlrdata->curpropboundstag;
2984 
2985  return SCIP_OKAY;
2986 }
2987 
2988 /** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2989  *
2990  * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2991  *
2992  * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2993  * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2994  */
2995 static
2997  SCIP* scip, /**< SCIP data structure */
2998  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2999  SCIP_CONS** conss, /**< constraints to propagate */
3000  int nconss, /**< total number of constraints */
3001  SCIP_RESULT* result, /**< pointer to store the result */
3002  int* nchgbds /**< buffer to add the number of changed bounds */
3003  )
3004 {
3005  SCIP_CONSDATA* consdata;
3006  SCIP_EXPRITER* it;
3007  SCIP_EXPR* expr;
3008  SCIP_EXPR_OWNERDATA* ownerdata;
3009  SCIP_Bool cutoff = FALSE;
3010  int ntightenings;
3011  int c;
3012  int e;
3013 
3014  assert(scip != NULL);
3015  assert(conshdlr != NULL);
3016  assert(conss != NULL);
3017  assert(nconss >= 0);
3018  assert(result != NULL);
3019  assert(nchgbds != NULL);
3020  assert(*nchgbds >= 0);
3021 
3022  assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
3023  assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
3024  assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
3025 
3026  *result = SCIP_DIDNOTFIND;
3027 
3028  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3030 
3031  for( c = 0; c < nconss && !cutoff; ++c )
3032  {
3033  /* skip deleted, non-active, or propagation-disabled constraints */
3034  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
3035  continue;
3036 
3037  consdata = SCIPconsGetData(conss[c]);
3038  assert(consdata != NULL);
3039 
3040  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
3041  {
3042  ownerdata = SCIPexprGetOwnerData(expr);
3043  assert(ownerdata != NULL);
3044 
3045  /* call reverseprop for those nlhdlr that participate in this expr's activity computation
3046  * this will propagate the current activity
3047  */
3048  for( e = 0; e < ownerdata->nenfos; ++e )
3049  {
3050  SCIP_NLHDLR* nlhdlr;
3051  assert(ownerdata->enfos[e] != NULL);
3052 
3053  nlhdlr = ownerdata->enfos[e]->nlhdlr;
3054  assert(nlhdlr != NULL);
3055  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
3056  continue;
3057 
3058  SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
3059  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
3060  ntightenings = 0;
3061  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
3062  SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
3063 
3064  if( cutoff )
3065  {
3066  /* stop everything if we detected infeasibility */
3067  SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3068  *result = SCIP_CUTOFF;
3069  break;
3070  }
3071 
3072  assert(ntightenings >= 0);
3073  if( ntightenings > 0 )
3074  {
3075  *nchgbds += ntightenings;
3076  *result = SCIP_REDUCEDDOM;
3077  }
3078  }
3079  }
3080  }
3081 
3082  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
3083  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
3084  assert(ntightenings >= 0);
3085 
3086  if( cutoff )
3087  {
3088  SCIPdebugMsg(scip, " -> cutoff\n");
3089  *result = SCIP_CUTOFF;
3090  }
3091  else if( ntightenings > 0 )
3092  {
3093  *nchgbds += ntightenings;
3094  *result = SCIP_REDUCEDDOM;
3095  }
3096 
3097  SCIPfreeExpriter(&it);
3098 
3099  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
3100  ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
3101 
3102  return SCIP_OKAY;
3103 }
3104 
3105 /** propagates variable locks through expression and adds locks to variables */
3106 static
3108  SCIP* scip, /**< SCIP data structure */
3109  SCIP_EXPR* expr, /**< expression */
3110  int nlockspos, /**< number of positive locks */
3111  int nlocksneg /**< number of negative locks */
3112  )
3113 {
3114  SCIP_EXPR_OWNERDATA* ownerdata;
3115  SCIP_EXPRITER* it;
3116  SCIP_EXPRITER_USERDATA ituserdata;
3117 
3118  assert(expr != NULL);
3119 
3120  /* if no locks, then nothing to propagate */
3121  if( nlockspos == 0 && nlocksneg == 0 )
3122  return SCIP_OKAY;
3123 
3124  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3127  assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3128 
3129  /* store locks in root node */
3130  ituserdata.intvals[0] = nlockspos;
3131  ituserdata.intvals[1] = nlocksneg;
3132  SCIPexpriterSetCurrentUserData(it, ituserdata);
3133 
3134  while( !SCIPexpriterIsEnd(it) )
3135  {
3136  /* collect locks */
3137  ituserdata = SCIPexpriterGetCurrentUserData(it);
3138  nlockspos = ituserdata.intvals[0];
3139  nlocksneg = ituserdata.intvals[1];
3140 
3141  ownerdata = SCIPexprGetOwnerData(expr);
3142 
3143  switch( SCIPexpriterGetStageDFS(it) )
3144  {
3146  {
3147  if( SCIPisExprVar(scip, expr) )
3148  {
3149  /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3150  SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3151  }
3152 
3153  /* add locks to expression */
3154  ownerdata->nlockspos += nlockspos;
3155  ownerdata->nlocksneg += nlocksneg;
3156 
3157  /* add monotonicity information if expression has been locked for the first time */
3158  if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3160  {
3161  int i;
3162 
3163  assert(ownerdata->monotonicity == NULL);
3164  assert(ownerdata->monotonicitysize == 0);
3165 
3166  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3167  ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3168 
3169  /* store the monotonicity for each child */
3170  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3171  {
3172  SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3173  }
3174  }
3175  break;
3176  }
3177 
3179  {
3180  /* remove monotonicity information if expression has been unlocked */
3181  if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3182  {
3183  assert(ownerdata->monotonicitysize > 0);
3184  /* keep this assert for checking whether someone changed an expression without updating locks properly */
3185  assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3186 
3187  SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3188  ownerdata->monotonicitysize = 0;
3189  }
3190  break;
3191  }
3192 
3194  {
3195  SCIP_MONOTONE monotonicity;
3196 
3197  /* get monotonicity of child */
3198  /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3199  * SCIPcallExprMonotonicity
3200  */
3201  monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3202 
3203  /* compute resulting locks of the child expression */
3204  switch( monotonicity )
3205  {
3206  case SCIP_MONOTONE_INC:
3207  ituserdata.intvals[0] = nlockspos;
3208  ituserdata.intvals[1] = nlocksneg;
3209  break;
3210  case SCIP_MONOTONE_DEC:
3211  ituserdata.intvals[0] = nlocksneg;
3212  ituserdata.intvals[1] = nlockspos;
3213  break;
3214  case SCIP_MONOTONE_UNKNOWN:
3215  ituserdata.intvals[0] = nlockspos + nlocksneg;
3216  ituserdata.intvals[1] = nlockspos + nlocksneg;
3217  break;
3218  case SCIP_MONOTONE_CONST:
3219  ituserdata.intvals[0] = 0;
3220  ituserdata.intvals[1] = 0;
3221  break;
3222  }
3223  /* set locks in child expression */
3224  SCIPexpriterSetChildUserData(it, ituserdata);
3225 
3226  break;
3227  }
3228 
3229  default :
3230  /* you should never be here */
3231  SCIPABORT();
3232  break;
3233  }
3234 
3235  expr = SCIPexpriterGetNext(it);
3236  }
3237 
3238  SCIPfreeExpriter(&it);
3239 
3240  return SCIP_OKAY;
3241 }
3242 
3243 /** main function for adding locks to expressions and variables
3244  *
3245  * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3246  * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3247  * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3248  * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3249  * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3250  * the computed monotonicity information of each expression until all locks of an expression have been removed,
3251  * which implies that updating the monotonicity information during the next locking of this expression does not
3252  * break existing locks.
3253  *
3254  * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3255  * locks from an expression and repropagating them after the structural changes have been applied.
3256  * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3257  * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3258  */
3259 static
3261  SCIP* scip, /**< SCIP data structure */
3262  SCIP_CONS* cons, /**< nonlinear constraint */
3263  int nlockspos, /**< number of positive rounding locks */
3264  int nlocksneg /**< number of negative rounding locks */
3265  )
3266 {
3267  SCIP_CONSDATA* consdata;
3268 
3269  assert(cons != NULL);
3270 
3271  if( nlockspos == 0 && nlocksneg == 0 )
3272  return SCIP_OKAY;
3273 
3274  consdata = SCIPconsGetData(cons);
3275  assert(consdata != NULL);
3276 
3277  /* no constraint sides -> nothing to lock */
3278  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3279  return SCIP_OKAY;
3280 
3281  /* remember locks */
3282  consdata->nlockspos += nlockspos;
3283  consdata->nlocksneg += nlocksneg;
3284 
3285  assert(consdata->nlockspos >= 0);
3286  assert(consdata->nlocksneg >= 0);
3287 
3288  /* compute locks for lock propagation */
3289  if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3290  {
3291  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3292  }
3293  else if( !SCIPisInfinity(scip, consdata->rhs) )
3294  {
3295  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3296  }
3297  else
3298  {
3299  assert(!SCIPisInfinity(scip, -consdata->lhs));
3300  SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3301  }
3302 
3303  return SCIP_OKAY;
3304 }
3305 
3306 /** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3307 static
3309  SCIP* scip, /**< SCIP data structure */
3310  SCIP_CONS* cons /**< nonlinear constraint */
3311  )
3312 {
3313  SCIP_CONSDATA* consdata;
3314 
3315  assert(scip != NULL);
3316  assert(cons != NULL);
3317 
3318  consdata = SCIPconsGetData(cons);
3319  assert(consdata != NULL);
3320  assert(consdata->expr != NULL);
3321 
3322  if( consdata->nlrow != NULL )
3323  {
3324  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3325  }
3326 
3327  /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3328  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3329  0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3330 
3331  if( SCIPisExprSum(scip, consdata->expr) )
3332  {
3333  /* if root is a sum, then split into linear and nonlinear terms */
3334  SCIP_EXPR* nonlinpart;
3335  SCIP_EXPR* child;
3336  SCIP_Real* coefs;
3337  int i;
3338 
3339  coefs = SCIPgetCoefsExprSum(consdata->expr);
3340 
3341  /* constant term of sum */
3342  SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3343 
3344  /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3345  SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3346 
3347  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3348  {
3349  child = SCIPexprGetChildren(consdata->expr)[i];
3350  if( SCIPisExprVar(scip, child) )
3351  {
3352  /* linear term */
3353  SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3354  }
3355  else
3356  {
3357  /* nonlinear term */
3358  SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3359  }
3360  }
3361 
3362  if( SCIPexprGetNChildren(nonlinpart) > 0 )
3363  {
3364  /* add expression to nlrow (this will make a copy) */
3365  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3366  }
3367  SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3368  }
3369  else
3370  {
3371  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3372  }
3373 
3374  return SCIP_OKAY;
3375 }
3376 
3377 /** compares enfodata by enforcement priority of nonlinear handler
3378  *
3379  * If handlers have same enforcement priority, then compare by detection priority, then by name.
3380  */
3381 static
3382 SCIP_DECL_SORTPTRCOMP(enfodataCmp)
3384  SCIP_NLHDLR* h1;
3385  SCIP_NLHDLR* h2;
3386 
3387  assert(elem1 != NULL);
3388  assert(elem2 != NULL);
3389 
3390  h1 = ((EXPRENFO*)elem1)->nlhdlr;
3391  h2 = ((EXPRENFO*)elem2)->nlhdlr;
3392 
3393  assert(h1 != NULL);
3394  assert(h2 != NULL);
3395 
3398 
3401 
3402  return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3403 }
3404 
3405 /** install nlhdlrs in one expression */
3406 static
3408  SCIP* scip, /**< SCIP data structure */
3409  SCIP_EXPR* expr, /**< expression for which to run detection routines */
3410  SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3411  )
3412 {
3413  SCIP_EXPR_OWNERDATA* ownerdata;
3414  SCIP_CONSHDLRDATA* conshdlrdata;
3415  SCIP_NLHDLR_METHOD enforcemethodsallowed;
3416  SCIP_NLHDLR_METHOD enforcemethods;
3417  SCIP_NLHDLR_METHOD enforcemethodsnew;
3418  SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3419  SCIP_NLHDLR_METHOD nlhdlrparticipating;
3420  SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3421  int enfossize; /* allocated length of expr->enfos array */
3422  int h;
3423 
3424  assert(expr != NULL);
3425 
3426  ownerdata = SCIPexprGetOwnerData(expr);
3427  assert(ownerdata != NULL);
3428 
3429  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3430  assert(conshdlrdata != NULL);
3431  assert(conshdlrdata->auxvarid >= 0);
3432  assert(!conshdlrdata->indetect);
3433 
3434  /* there should be no enforcer yet and detection should not even have considered expr yet */
3435  assert(ownerdata->nenfos < 0);
3436  assert(ownerdata->enfos == NULL);
3437 
3438  /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3439  * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3440  * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3441  * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3442  * - if no one uses activity, then do not need activity methods
3443  */
3444  enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3445  if( ownerdata->nauxvaruses == 0 )
3446  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3447  else
3448  {
3449  if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3450  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3451  if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3452  enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3453  }
3454  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3455  enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3456 
3457  /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3458  assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3459 
3460  /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3461  enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3462 
3463  ownerdata->nenfos = 0;
3464  enfossize = 2;
3465  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3466  conshdlrdata->indetect = TRUE;
3467 
3468  SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3469  cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3470  (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3471  (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3472  (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3473 
3474  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3475  {
3476  SCIP_NLHDLR* nlhdlr;
3477 
3478  nlhdlr = conshdlrdata->nlhdlrs[h];
3479  assert(nlhdlr != NULL);
3480 
3481  /* skip disabled nlhdlrs */
3482  if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3483  continue;
3484 
3485  /* call detect routine of nlhdlr */
3486  nlhdlrexprdata = NULL;
3487  enforcemethodsnew = enforcemethods;
3488  nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3489  conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3490  conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3491  /* coverity[forward_null] */
3492  SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3493 
3494  /* nlhdlr might have claimed more than needed: clean up sepa flags */
3495  nlhdlrparticipating &= enforcemethodsallowed;
3496 
3497  /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3498  assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3499 
3500  /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3501  * They are also cleaned up here to ensure that only the needed methods are claimed.
3502  */
3503  nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3504 
3505  /* nlhdlr needs to participate for the methods it is enforcing */
3506  assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3507 
3508  if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3509  {
3510  /* nlhdlr might not have detected anything, or all set flags might have been removed by
3511  * clean up; in the latter case, we may need to free nlhdlrexprdata */
3512 
3513  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3514  if( nlhdlrexprdata != NULL )
3515  {
3516  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3517  }
3518  /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3519  assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3520 
3521  SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3522 
3523  continue;
3524  }
3525 
3526  SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3527  SCIPnlhdlrGetName(nlhdlr),
3528  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3529  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3530  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3531 
3532  /* store nlhdlr and its data */
3533  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3534  SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3535  ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3536  ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3537  ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3538  ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3539  ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3540  ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3541  ownerdata->nenfos++;
3542 
3543  /* update enforcement flags */
3544  enforcemethods = enforcemethodsnew;
3545  }
3546 
3547  conshdlrdata->indetect = FALSE;
3548 
3549  /* stop if an enforcement method is missing but we are already in solving stage
3550  * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3551  */
3552  if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3553  {
3554  SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3555  return SCIP_ERROR;
3556  }
3557 
3558  assert(ownerdata->nenfos > 0);
3559 
3560  /* sort nonlinear handlers by enforcement priority, in decreasing order */
3561  if( ownerdata->nenfos > 1 )
3562  SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3563 
3564  /* resize enfos array to be nenfos long */
3565  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3566 
3567  return SCIP_OKAY;
3568 }
3569 
3570 /** detect nlhdlrs that can handle the expressions */
3571 static
3573  SCIP* scip, /**< SCIP data structure */
3574  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3575  SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3576  int nconss /**< total number of constraints */
3577  )
3578 {
3579  SCIP_CONSHDLRDATA* conshdlrdata;
3580  SCIP_CONSDATA* consdata;
3581  SCIP_EXPR* expr;
3582  SCIP_EXPR_OWNERDATA* ownerdata;
3583  SCIP_EXPRITER* it;
3584  int i;
3585 
3586  assert(conss != NULL || nconss == 0);
3587  assert(nconss >= 0);
3588  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 */
3589 
3590  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3591  assert(conshdlrdata != NULL);
3592 
3593  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3595 
3596  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3597  {
3598  /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3599  * for example, this happens if globally valid nonlinear constraints are added during the tree search
3600  */
3602  conshdlrdata->globalbounds = TRUE;
3603  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3604  }
3605 
3606  for( i = 0; i < nconss; ++i )
3607  {
3608  assert(conss != NULL && conss[i] != NULL);
3609 
3610  consdata = SCIPconsGetData(conss[i]);
3611  assert(consdata != NULL);
3612  assert(consdata->expr != NULL);
3613 
3614  /* if a constraint is separated, we currently need it to be initial, too
3615  * this is because INITLP will create the auxiliary variables that are used for any separation
3616  * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3617  */
3618  assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3619 
3620  ownerdata = SCIPexprGetOwnerData(consdata->expr);
3621  assert(ownerdata != NULL);
3622 
3623  /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3624  * then we would normally skip to run DETECT again
3625  * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3626  * thus, if expr is the root expression, we rerun DETECT
3627  */
3628  if( ownerdata->nenfos > 0 )
3629  {
3630  SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3631  assert(ownerdata->nenfos < 0);
3632  }
3633 
3634  /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3635  * this way we can treat the root expression like any other expression when enforcing via separation
3636  * if constraint will be propagated, then register activity usage of root expression
3637  * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3638  */
3639  conshdlrdata->indetect = TRUE;
3640  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, consdata->expr,
3641  SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3642  SCIPconsIsPropagated(conss[i]),
3643  FALSE, FALSE) );
3644  conshdlrdata->indetect = FALSE;
3645 
3646  /* compute integrality information for all subexpressions */
3647  SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3648 
3649  /* run detectNlhdlr on all expr where required */
3650  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3651  {
3652  ownerdata = SCIPexprGetOwnerData(expr);
3653  assert(ownerdata != NULL);
3654 
3655  /* skip exprs that we already looked at */
3656  if( ownerdata->nenfos >= 0 )
3657  continue;
3658 
3659  /* if there is use of the auxvar, then someone requires that
3660  * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3661  * thus, we need to find nlhdlrs that separate or estimate
3662  * if there is use of the activity, then there is someone requiring that
3663  * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3664  * thus, we need to find nlhdlrs that do interval-evaluation
3665  */
3666  if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3667  {
3668  SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3669 
3670  assert(ownerdata->nenfos >= 0);
3671  }
3672  else
3673  {
3674  /* remember that we looked at this expression during detectNlhdlrs
3675  * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3676  * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3677  * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3678  */
3679  ownerdata->nenfos = 0;
3680  }
3681  }
3682 
3683  /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3684  if( SCIPconsIsPropagated(conss[i]) )
3685  consdata->ispropagated = FALSE;
3686  }
3687 
3688  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3689  {
3690  /* ensure that the local bounds are used again when reevaluating the expressions later;
3691  * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3692  */
3694  conshdlrdata->globalbounds = FALSE;
3695  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3696  }
3697  else
3698  {
3699  /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3701  }
3702 
3703  SCIPfreeExpriter(&it);
3704 
3705  return SCIP_OKAY;
3706 }
3707 
3708 /** initializes (pre)solving data of constraints
3709  *
3710  * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3711  * not be modified.
3712  * In particular, this function
3713  * - runs the detection method of nlhldrs
3714  * - looks for unlocked linear variables
3715  * - checks curvature (if not in presolve)
3716  * - creates and add row to NLP (if not in presolve)
3717  *
3718  * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3719  * e.g., it should be called in INITSOL and for constraints that are added during solve.
3720  */
3721 static
3723  SCIP* scip, /**< SCIP data structure */
3724  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3725  SCIP_CONS** conss, /**< constraints */
3726  int nconss /**< number of constraints */
3727  )
3728 {
3729  int c;
3730 
3731  for( c = 0; c < nconss; ++c )
3732  {
3733  /* check for a linear variable that can be increase or decreased without harming feasibility */
3734  findUnlockedLinearVar(scip, conss[c]);
3735 
3737  {
3738  SCIP_CONSDATA* consdata;
3739  SCIP_Bool success = FALSE;
3740 
3741  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3742  assert(consdata != NULL);
3743  assert(consdata->expr != NULL);
3744 
3745  if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3746  {
3747  /* call the curvature detection algorithm of the convex nonlinear handler
3748  * Check only for those curvature that may result in a convex inequality, i.e.,
3749  * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3750  * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3751  */
3752  if( !SCIPisInfinity(scip, -consdata->lhs) )
3753  {
3754  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3755  if( success )
3756  consdata->curv = SCIP_EXPRCURV_CONCAVE;
3757  }
3758  if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3759  {
3760  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3761  if( success )
3762  consdata->curv = SCIP_EXPRCURV_CONVEX;
3763  }
3764  }
3765  else
3766  {
3767  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3768  {
3769  SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3770  consdata->curv = SCIP_EXPRCURV_LINEAR;
3771  }
3772  else
3773  {
3774  consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3775  }
3776  }
3777  SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3778 
3779  /* add nlrow representation to NLP, if NLP had been constructed */
3780  if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3781  {
3782  if( consdata->nlrow == NULL )
3783  {
3784  SCIP_CALL( createNlRow(scip, conss[c]) );
3785  assert(consdata->nlrow != NULL);
3786  }
3787  SCIPnlrowSetCurvature(consdata->nlrow, consdata->curv);
3788  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3789  }
3790  }
3791  }
3792 
3793  /* register non linear handlers */
3794  SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3795 
3796  return SCIP_OKAY;
3797 }
3798 
3799 /** deinitializes (pre)solving data of constraints
3800  *
3801  * This removes the initialization data created in initSolve().
3802  *
3803  * This function can be called in presolve and solve.
3804  *
3805  * TODO At the moment, it should not be called for a constraint if there are other constraints
3806  * that use the same expressions but still require their nlhdlr.
3807  * We should probably only decrement the auxvar and activity usage for the root expr and then
3808  * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3809  */
3810 static
3812  SCIP* scip, /**< SCIP data structure */
3813  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3814  SCIP_CONS** conss, /**< constraints */
3815  int nconss /**< number of constraints */
3816  )
3817 {
3818  SCIP_EXPRITER* it;
3819  SCIP_EXPR* expr;
3820  SCIP_CONSDATA* consdata;
3821  SCIP_Bool rootactivityvalid;
3822  int c;
3823 
3824  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3827 
3828  /* call deinitialization callbacks of expression and nonlinear handlers
3829  * free nonlinear handlers information from expressions
3830  * remove auxiliary variables and nactivityuses counts from expressions
3831  */
3832  for( c = 0; c < nconss; ++c )
3833  {
3834  assert(conss != NULL);
3835  assert(conss[c] != NULL);
3836 
3837  consdata = SCIPconsGetData(conss[c]);
3838  assert(consdata != NULL);
3839  assert(consdata->expr != NULL);
3840 
3841  /* check and remember whether activity in root is valid */
3842  rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3843 
3844  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3845  {
3846  SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3847 
3848  /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3849  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3850 
3851  /* remove quadratic info */
3852  SCIPfreeExprQuadratic(scip, expr);
3853 
3854  if( rootactivityvalid )
3855  {
3856  /* ensure activity is valid if consdata->expr activity is valid
3857  * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3858  * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3859  * so this childs activity would be invalid, which can generate confusion
3860  */
3861  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
3862  }
3863  }
3864 
3865  if( consdata->nlrow != NULL )
3866  {
3867  /* remove row from NLP, if still in solving
3868  * if we are in exitsolve, the whole NLP will be freed anyway
3869  */
3870  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3871  {
3872  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3873  }
3874 
3875  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3876  }
3877 
3878  /* forget about linear variables that can be increased or decreased without harming feasibility */
3879  consdata->linvardecr = NULL;
3880  consdata->linvarincr = NULL;
3881 
3882  /* forget about curvature */
3883  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3884  }
3885 
3886  SCIPfreeExpriter(&it);
3887 
3888  return SCIP_OKAY;
3889 }
3890 
3891 /** helper method to decide whether a given expression is product of at least two binary variables */
3892 static
3894  SCIP* scip, /**< SCIP data structure */
3895  SCIP_EXPR* expr /**< expression */
3896  )
3897 {
3898  int i;
3899 
3900  assert(expr != NULL);
3901 
3902  /* check whether the expression is a product */
3903  if( !SCIPisExprProduct(scip, expr) )
3904  return FALSE;
3905 
3906  /* don't consider products with a coefficient != 1 and products with a single child
3907  * simplification will take care of this expression later
3908  */
3909  if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3910  return FALSE;
3911 
3912  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3913  {
3914  SCIP_EXPR* child;
3915  SCIP_VAR* var;
3916  SCIP_Real ub;
3917  SCIP_Real lb;
3918 
3919  child = SCIPexprGetChildren(expr)[i];
3920  assert(child != NULL);
3921 
3922  if( !SCIPisExprVar(scip, child) )
3923  return FALSE;
3924 
3925  var = SCIPgetVarExprVar(child);
3926  lb = SCIPvarGetLbLocal(var);
3927  ub = SCIPvarGetUbLocal(var);
3928 
3929  /* check whether variable is integer and has [0,1] as variable bounds */
3930  if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3931  return FALSE;
3932  }
3933 
3934  return TRUE;
3935 }
3936 
3937 /** helper method to collect all bilinear binary product terms */
3938 static
3940  SCIP* scip, /**< SCIP data structure */
3941  SCIP_EXPR* sumexpr, /**< sum expression */
3942  SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3943  SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3944  int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3945  int* nterms /**< pointer to store the total number of bilinear binary terms */
3946  )
3947 {
3948  int i;
3949 
3950  assert(sumexpr != NULL);
3951  assert(SCIPisExprSum(scip, sumexpr));
3952  assert(xs != NULL);
3953  assert(ys != NULL);
3954  assert(childidxs != NULL);
3955  assert(nterms != NULL);
3956 
3957  *nterms = 0;
3958 
3959  for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3960  {
3961  SCIP_EXPR* child;
3962 
3963  child = SCIPexprGetChildren(sumexpr)[i];
3964  assert(child != NULL);
3965 
3966  if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3967  {
3970 
3971  assert(x != NULL);
3972  assert(y != NULL);
3973 
3974  if( x != y )
3975  {
3976  xs[*nterms] = x;
3977  ys[*nterms] = y;
3978  childidxs[*nterms] = i;
3979  ++(*nterms);
3980  }
3981  }
3982  }
3983 
3984  return SCIP_OKAY;
3985 }
3986 
3987 /** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3988 static
3990  SCIP* scip, /**< SCIP data structure */
3991  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3992  SCIP_CONS* cons, /**< constraint */
3993  SCIP_VAR* facvar, /**< variable that has been factorized */
3994  SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3995  SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3996  int nvars, /**< total number of variables in sum_j c_ij x_j */
3997  SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3998  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3999  )
4000 {
4001  SCIP_VAR* auxvar;
4002  SCIP_CONS* newcons;
4003  SCIP_Real minact = 0.0;
4004  SCIP_Real maxact = 0.0;
4005  SCIP_Bool integral = TRUE;
4006  char name [SCIP_MAXSTRLEN];
4007  int i;
4008 
4009  assert(facvar != NULL);
4010  assert(vars != NULL);
4011  assert(nvars > 1);
4012  assert(newexpr != NULL);
4013 
4014  /* compute minimum and maximum activity of sum_j c_ij x_j */
4015  /* 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 */
4016  for( i = 0; i < nvars; ++i )
4017  {
4018  minact += MIN(coefs[i], 0.0);
4019  maxact += MAX(coefs[i], 0.0);
4020  integral = integral && SCIPisIntegral(scip, coefs[i]);
4021  }
4022  assert(minact <= maxact);
4023 
4024  /* create and add auxiliary variable */
4025  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4026  SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
4027  SCIP_CALL( SCIPaddVar(scip, auxvar) );
4028 
4029  /* create and add z - maxact x <= 0 */
4030  if( !SCIPisZero(scip, maxact) )
4031  {
4032  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4033  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
4034  SCIP_CALL( SCIPaddCons(scip, newcons) );
4035  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4036  if( naddconss != NULL )
4037  ++(*naddconss);
4038  }
4039 
4040  /* create and add 0 <= z - minact x */
4041  if( !SCIPisZero(scip, minact) )
4042  {
4043  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4044  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
4045  SCIP_CALL( SCIPaddCons(scip, newcons) );
4046  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4047  if( naddconss != NULL )
4048  ++(*naddconss);
4049  }
4050 
4051  /* create and add minact <= sum_j c_j x_j - z + minact x_i */
4052  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4053  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
4054  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4055  if( !SCIPisZero(scip, minact) )
4056  {
4057  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
4058  }
4059  SCIP_CALL( SCIPaddCons(scip, newcons) );
4060  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4061  if( naddconss != NULL )
4062  ++(*naddconss);
4063 
4064  /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4065  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4066  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4067  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4068  if( !SCIPisZero(scip, maxact) )
4069  {
4070  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4071  }
4072  SCIP_CALL( SCIPaddCons(scip, newcons) );
4073  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4074  if( naddconss != NULL )
4075  ++(*naddconss);
4076 
4077  /* create variable expression */
4078  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4079 
4080  /* release auxvar */
4081  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4082 
4083  return SCIP_OKAY;
4084 }
4085 
4086 /** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4087 static
4089  SCIP* scip, /**< SCIP data structure */
4090  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4091  SCIP_CONS* cons, /**< constraint */
4092  SCIP_EXPR* sumexpr, /**< expression */
4093  int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4094  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4095  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4096  )
4097 {
4098  SCIP_EXPR** exprs = NULL;
4099  SCIP_VAR** tmpvars = NULL;
4100  SCIP_VAR** vars = NULL;
4101  SCIP_VAR** xs = NULL;
4102  SCIP_VAR** ys = NULL;
4103  SCIP_Real* exprcoefs = NULL;
4104  SCIP_Real* tmpcoefs = NULL;
4105  SCIP_Real* sumcoefs;
4106  SCIP_Bool* isused = NULL;
4107  int* childidxs = NULL;
4108  int* count = NULL;
4109  int nchildren;
4110  int nexprs = 0;
4111  int nterms;
4112  int nvars;
4113  int ntotalvars;
4114  int i;
4115 
4116  assert(sumexpr != NULL);
4117  assert(minterms > 1);
4118  assert(newexpr != NULL);
4119 
4120  *newexpr = NULL;
4121 
4122  /* check whether sumexpr is indeed a sum */
4123  if( !SCIPisExprSum(scip, sumexpr) )
4124  return SCIP_OKAY;
4125 
4126  nchildren = SCIPexprGetNChildren(sumexpr);
4127  sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4128  nvars = SCIPgetNVars(scip);
4129  ntotalvars = SCIPgetNTotalVars(scip);
4130 
4131  /* check whether there are enough terms available */
4132  if( nchildren < minterms )
4133  return SCIP_OKAY;
4134 
4135  /* allocate memory */
4136  SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4137  SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4138  SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4139 
4140  /* collect all bilinear binary product terms */
4141  SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4142 
4143  /* check whether there are enough terms available */
4144  if( nterms < minterms )
4145  goto TERMINATE;
4146 
4147  /* store how often each variable appears in a bilinear binary product */
4148  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
4149  SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4150  SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4151 
4152  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4153  SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4154  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4155  SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4156 
4157  for( i = 0; i < nterms; ++i )
4158  {
4159  int xidx;
4160  int yidx;
4161 
4162  assert(xs[i] != NULL);
4163  assert(ys[i] != NULL);
4164 
4165  xidx = SCIPvarGetIndex(xs[i]);
4166  assert(xidx < ntotalvars);
4167  yidx = SCIPvarGetIndex(ys[i]);
4168  assert(yidx < ntotalvars);
4169 
4170  ++count[xidx];
4171  ++count[yidx];
4172 
4173  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4174  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4175  }
4176 
4177  /* sort variables; don't change order of count array because it depends on problem indices */
4178  {
4179  int* tmpcount;
4180 
4181  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4182  SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4183  SCIPfreeBufferArray(scip, &tmpcount);
4184  }
4185 
4186  for( i = 0; i < nvars; ++i )
4187  {
4188  SCIP_VAR* facvar = vars[i];
4189  int ntmpvars = 0;
4190  int j;
4191 
4192  /* skip candidate if there are not enough terms left */
4193  if( count[SCIPvarGetIndex(vars[i])] < minterms )
4194  continue;
4195 
4196  SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4197 
4198  /* collect variables for x_i * sum_j c_ij x_j */
4199  for( j = 0; j < nterms; ++j )
4200  {
4201  int childidx = childidxs[j];
4202  assert(childidx >= 0 && childidx < nchildren);
4203 
4204  if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4205  {
4206  SCIP_Real coef;
4207  int xidx;
4208  int yidx;
4209 
4210  coef = sumcoefs[childidx];
4211  assert(coef != 0.0);
4212 
4213  /* collect corresponding variable */
4214  tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4215  tmpcoefs[ntmpvars] = coef;
4216  ++ntmpvars;
4217 
4218  /* update counters */
4219  xidx = SCIPvarGetIndex(xs[j]);
4220  assert(xidx < ntotalvars);
4221  yidx = SCIPvarGetIndex(ys[j]);
4222  assert(yidx < ntotalvars);
4223  --count[xidx];
4224  --count[yidx];
4225  assert(count[xidx] >= 0);
4226  assert(count[yidx] >= 0);
4227 
4228  /* mark term to be used */
4229  isused[childidx] = TRUE;
4230  }
4231  }
4232  assert(ntmpvars >= minterms);
4233  assert(SCIPvarGetIndex(facvar) < ntotalvars);
4234  assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4235 
4236  /* create required constraints and store the generated expression */
4237  SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4238  exprcoefs[nexprs] = 1.0;
4239  ++nexprs;
4240  }
4241 
4242  /* factorization was only successful if at least one expression has been generated */
4243  if( nexprs > 0 )
4244  {
4245  int nexprsold = nexprs;
4246 
4247  /* add all children of the sum that have not been used */
4248  for( i = 0; i < nchildren; ++i )
4249  {
4250  if( !isused[i] )
4251  {
4252  exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4253  exprcoefs[nexprs] = sumcoefs[i];
4254  ++nexprs;
4255  }
4256  }
4257 
4258  /* create a new sum expression */
4259  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4260 
4261  /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4262  for( i = 0; i < nexprsold; ++i )
4263  {
4264  SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4265  }
4266  }
4267 
4268 TERMINATE:
4269  /* free memory */
4270  SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4271  SCIPfreeBufferArrayNull(scip, &tmpvars);
4272  SCIPfreeBufferArrayNull(scip, &exprcoefs);
4273  SCIPfreeBufferArrayNull(scip, &exprs);
4274  SCIPfreeBufferArrayNull(scip, &vars);
4275  SCIPfreeBufferArrayNull(scip, &isused);
4276  SCIPfreeBufferArrayNull(scip, &count);
4277  SCIPfreeBufferArray(scip, &childidxs);
4278  SCIPfreeBufferArray(scip, &ys);
4279  SCIPfreeBufferArray(scip, &xs);
4280 
4281  return SCIP_OKAY;
4282 }
4283 
4284 /** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4285 static
4287  SCIP* scip, /**< SCIP data structure */
4288  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4289  SCIP_EXPR* prodexpr, /**< product expression */
4290  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4291  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4292  SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4293  )
4294 {
4295  SCIP_VAR** vars;
4296  SCIP_CONS* cons;
4297  SCIP_Real* coefs;
4298  SCIP_VAR* w;
4299  char* name;
4300  int nchildren;
4301  int i;
4302 
4303  assert(conshdlr != NULL);
4304  assert(prodexpr != NULL);
4305  assert(SCIPisExprProduct(scip, prodexpr));
4306  assert(newexpr != NULL);
4307 
4308  nchildren = SCIPexprGetNChildren(prodexpr);
4309  assert(nchildren >= 2);
4310 
4311  /* memory to store the variables of the variable expressions (+1 for w) and their name */
4312  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4313  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4314  SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4315 
4316  /* prepare the names of the variable and the constraints */
4317  strcpy(name, "binreform");
4318  for( i = 0; i < nchildren; ++i )
4319  {
4320  vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4321  coefs[i] = 1.0;
4322  assert(vars[i] != NULL);
4323  (void) strcat(name, "_");
4324  (void) strcat(name, SCIPvarGetName(vars[i]));
4325  }
4326 
4327  /* create and add variable */
4328  SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4329  SCIP_CALL( SCIPaddVar(scip, w) );
4330  SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4331 
4332  /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4333  if( nchildren == 2 && !empathy4and )
4334  {
4335  SCIP_VAR* x = vars[0];
4336  SCIP_VAR* y = vars[1];
4337 
4338  assert(x != NULL);
4339  assert(y != NULL);
4340  assert(x != y);
4341 
4342  /* create and add x - w >= 0 */
4343  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4344  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4345  SCIP_CALL( SCIPaddCons(scip, cons) );
4346  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4347 
4348  /* create and add y - w >= 0 */
4349  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4350  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4351  SCIP_CALL( SCIPaddCons(scip, cons) );
4352  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4353 
4354  /* create and add x + y - w <= 1 */
4355  vars[2] = w;
4356  coefs[2] = -1.0;
4357  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4358  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4359  SCIP_CALL( SCIPaddCons(scip, cons) );
4360  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4361 
4362  /* update number of added constraints */
4363  if( naddconss != NULL )
4364  *naddconss += 3;
4365  }
4366  else
4367  {
4368  /* create, add, and release AND constraint */
4369  SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4370  SCIP_CALL( SCIPaddCons(scip, cons) );
4371  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4372  SCIPdebugMsg(scip, " create AND constraint\n");
4373 
4374  /* update number of added constraints */
4375  if( naddconss != NULL )
4376  *naddconss += 1;
4377  }
4378 
4379  /* create variable expression */
4380  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4381 
4382  /* release created variable */
4383  SCIP_CALL( SCIPreleaseVar(scip, &w) );
4384 
4385  /* free memory */
4386  SCIPfreeBufferArray(scip, &name);
4387  SCIPfreeBufferArray(scip, &coefs);
4388  SCIPfreeBufferArray(scip, &vars);
4389 
4390  return SCIP_OKAY;
4391 }
4392 
4393 /** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4394 static
4396  SCIP* scip, /**< SCIP data structure */
4397  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4398  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4399  SCIP_EXPR* prodexpr, /**< product expression */
4400  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4401  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4402  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4403  )
4404 {
4405  SCIP_CONSHDLRDATA* conshdlrdata;
4406  int nchildren;
4407 
4408  assert(prodexpr != NULL);
4409  assert(newexpr != NULL);
4410 
4411  *newexpr = NULL;
4412 
4413  /* only consider products of binary variables */
4414  if( !isBinaryProduct(scip, prodexpr) )
4415  return SCIP_OKAY;
4416 
4417  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4418  assert(conshdlrdata != NULL);
4419  nchildren = SCIPexprGetNChildren(prodexpr);
4420  assert(nchildren >= 2);
4421 
4422  /* check whether there is already an expression that represents the product */
4423  if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4424  {
4425  *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4426  assert(*newexpr != NULL);
4427 
4428  /* capture expression */
4429  SCIPcaptureExpr(*newexpr);
4430  }
4431  else
4432  {
4433  SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4434 
4435  if( nchildren == 2 )
4436  {
4437  SCIP_CLIQUE** xcliques;
4438  SCIP_VAR* x;
4439  SCIP_VAR* y;
4440  SCIP_Bool found_clique = FALSE;
4441  int c;
4442 
4443  /* get variables from the product expression */
4444  x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4445  assert(x != NULL);
4446  y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4447  assert(y != NULL);
4448  assert(x != y);
4449 
4450  /* first try to find a clique containing both variables */
4451  xcliques = SCIPvarGetCliques(x, TRUE);
4452 
4453  /* look in cliques containing x */
4454  for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4455  {
4456  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4457  {
4458  /* create zero value expression */
4459  SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4460 
4461  if( nchgcoefs != NULL )
4462  *nchgcoefs += 1;
4463 
4464  found_clique = TRUE;
4465  break;
4466  }
4467 
4468  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4469  {
4470  /* create variable expression for x */
4471  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4472 
4473  if( nchgcoefs != NULL )
4474  *nchgcoefs += 2;
4475 
4476  found_clique = TRUE;
4477  break;
4478  }
4479  }
4480 
4481  if( !found_clique )
4482  {
4483  xcliques = SCIPvarGetCliques(x, FALSE);
4484 
4485  /* look in cliques containing complement of x */
4486  for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4487  {
4488  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4489  {
4490  /* create variable expression for y */
4491  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4492 
4493  if( nchgcoefs != NULL )
4494  *nchgcoefs += 1;
4495 
4496  found_clique = TRUE;
4497  break;
4498  }
4499 
4500  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4501  {
4502  /* create sum expression */
4503  SCIP_EXPR* sum_children[2];
4504  SCIP_Real sum_coefs[2];
4505  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4506  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4507  sum_coefs[0] = 1.0;
4508  sum_coefs[1] = 1.0;
4509  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4510 
4511  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4512  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4513 
4514  if( nchgcoefs != NULL )
4515  *nchgcoefs += 3;
4516 
4517  found_clique = TRUE;
4518  break;
4519  }
4520  }
4521  }
4522 
4523  /* if the variables are not in a clique, do standard linearization */
4524  if( !found_clique )
4525  {
4526  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4527  }
4528  }
4529  else
4530  {
4531  /* linearize binary product using an AND constraint because nchildren > 2 */
4532  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4533  }
4534 
4535  /* hash variable expression */
4536  SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4537  }
4538 
4539  return SCIP_OKAY;
4540 }
4541 
4542 /** helper function to replace binary products in a given constraint */
4543 static
4545  SCIP* scip, /**< SCIP data structure */
4546  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4547  SCIP_CONS* cons, /**< constraint */
4548  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4549  SCIP_EXPRITER* it, /**< expression iterator */
4550  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4551  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4552  )
4553 {
4554  SCIP_CONSHDLRDATA* conshdlrdata;
4555  SCIP_CONSDATA* consdata;
4556  SCIP_EXPR* expr;
4557 
4558  assert(conshdlr != NULL);
4559  assert(cons != NULL);
4560  assert(exprmap != NULL);
4561  assert(it != NULL);
4562 
4563  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4564  assert(conshdlrdata != NULL);
4565 
4566  consdata = SCIPconsGetData(cons);
4567  assert(consdata != NULL);
4568  assert(consdata->expr != NULL);
4569 
4570  SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4571 
4572  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4573  {
4574  SCIP_EXPR* newexpr = NULL;
4575  SCIP_EXPR* childexpr;
4576  int childexpridx;
4577 
4578  childexpridx = SCIPexpriterGetChildIdxDFS(it);
4579  assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4580  childexpr = SCIPexpriterGetChildExprDFS(it);
4581  assert(childexpr != NULL);
4582 
4583  /* try to factorize variables in a sum expression that contains several products of binary variables */
4584  if( conshdlrdata->reformbinprodsfac > 1 )
4585  {
4586  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4587  }
4588 
4589  /* try to create an expression that represents a product of binary variables */
4590  if( newexpr == NULL )
4591  {
4592  SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4593  }
4594 
4595  if( newexpr != NULL )
4596  {
4597  assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4598 
4599  /* replace product expression */
4600  SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4601 
4602  /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4603  SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4604 
4605  /* mark the constraint to not be simplified anymore */
4606  consdata->issimplified = FALSE;
4607  }
4608  }
4609 
4610  return SCIP_OKAY;
4611 }
4612 
4613 /** reformulates products of binary variables during presolving in the following way:
4614  *
4615  * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4616  * 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}:
4617  * \f[
4618  * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4619  * \f]
4620  *
4621  * 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$.
4622  * These cliques allow for a better reformulation. There are four cases:
4623  *
4624  * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4625  * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4626  * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4627  * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4628  *
4629  * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4630  *
4631  * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4632  * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4633  * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4634  * Such a lower sum is reformulated with only one extra variable w_i:
4635  * \f{align}{
4636  * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4637  * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4638  * \text{minact}\, x_i & \leq w_i, \\
4639  * w_i &\leq \text{maxact}\, x_i, \\
4640  * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4641  * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4642  * \f}
4643  * 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
4644  * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4645  * of terms are prioritized.
4646  */
4647 static
4649  SCIP* scip, /**< SCIP data structure */
4650  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4651  SCIP_CONS** conss, /**< constraints */
4652  int nconss, /**< total number of constraints */
4653  int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4654  int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4655  )
4656 {
4657  SCIP_CONSHDLRDATA* conshdlrdata;
4658  SCIP_HASHMAP* exprmap;
4659  SCIP_EXPRITER* it;
4660  int c;
4661 
4662  assert(conshdlr != NULL);
4663 
4664  /* no nonlinear constraints or binary variables -> skip */
4665  if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4666  return SCIP_OKAY;
4667  assert(conss != NULL);
4668 
4669  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4670  assert(conshdlrdata != NULL);
4671 
4672  /* create expression hash map */
4673  SCIP_CALL( SCIPhashmapCreate(&exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
4674 
4675  /* create expression iterator */
4676  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4679 
4680  SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4681 
4682  for( c = 0; c < nconss; ++c )
4683  {
4684  SCIP_CONSDATA* consdata;
4685  SCIP_EXPR* newexpr = NULL;
4686 
4687  assert(conss[c] != NULL);
4688 
4689  consdata = SCIPconsGetData(conss[c]);
4690  assert(consdata != NULL);
4691 
4692  /* try to reformulate the root expression */
4693  if( conshdlrdata->reformbinprodsfac > 1 )
4694  {
4695  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4696  }
4697 
4698  /* release the root node if another expression has been found */
4699  if( newexpr != NULL )
4700  {
4701  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4702  consdata->expr = newexpr;
4703 
4704  /* mark constraint to be not simplified anymore */
4705  consdata->issimplified = FALSE;
4706  }
4707 
4708  /* replace each product of binary variables separately */
4709  SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4710  }
4711 
4712  /* free memory */
4713  SCIPhashmapFree(&exprmap);
4714  SCIPfreeExpriter(&it);
4715 
4716  return SCIP_OKAY;
4717 }
4718 
4719 /** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4720  *
4721  * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4722  * Then scale by -1 if
4723  * - \f$n_+ < n_-\f$, or
4724  * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4725  */
4726 static
4728  SCIP* scip, /**< SCIP data structure */
4729  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4730  SCIP_CONS* cons, /**< nonlinear constraint */
4731  SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4732  )
4733 {
4734  SCIP_CONSDATA* consdata;
4735  int i;
4736 
4737  assert(cons != NULL);
4738 
4739  consdata = SCIPconsGetData(cons);
4740  assert(consdata != NULL);
4741 
4742  if( SCIPisExprSum(scip, consdata->expr) )
4743  {
4744  SCIP_Real* coefs;
4745  SCIP_Real constant;
4746  int nchildren;
4747  int counter = 0;
4748 
4749  coefs = SCIPgetCoefsExprSum(consdata->expr);
4750  constant = SCIPgetConstantExprSum(consdata->expr);
4751  nchildren = SCIPexprGetNChildren(consdata->expr);
4752 
4753  /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4754  if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4755  {
4756  SCIP_EXPR* expr;
4757  expr = consdata->expr;
4758 
4759  consdata->expr = SCIPexprGetChildren(expr)[0];
4760  assert(!SCIPisExprSum(scip, consdata->expr));
4761 
4762  SCIPcaptureExpr(consdata->expr);
4763 
4764  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4765  consdata->lhs = -consdata->lhs;
4766  consdata->rhs = -consdata->rhs;
4767 
4768  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4769  *changed = TRUE;
4770  return SCIP_OKAY;
4771  }
4772 
4773  /* compute n_+ - n_i */
4774  for( i = 0; i < nchildren; ++i )
4775  counter += coefs[i] > 0 ? 1 : -1;
4776 
4777  if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4778  {
4779  SCIP_EXPR* expr;
4780  SCIP_Real* newcoefs;
4781 
4782  /* allocate memory */
4783  SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4784 
4785  for( i = 0; i < nchildren; ++i )
4786  newcoefs[i] = -coefs[i];
4787 
4788  /* create a new sum expression */
4789  SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4790 
4791  /* replace expression in constraint data and scale sides */
4792  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4793  consdata->expr = expr;
4794  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4795  consdata->lhs = -consdata->lhs;
4796  consdata->rhs = -consdata->rhs;
4797 
4798  /* free memory */
4799  SCIPfreeBufferArray(scip, &newcoefs);
4800 
4801  *changed = TRUE;
4802  }
4803  }
4804 
4805  return SCIP_OKAY;
4806 }
4807 
4808 /** forbid multiaggrations of variables that appear nonlinear in constraints */
4809 static
4811  SCIP* scip, /**< SCIP data structure */
4812  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4813  SCIP_CONS** conss, /**< constraints */
4814  int nconss /**< number of constraints */
4815  )
4816 {
4817  SCIP_EXPRITER* it;
4818  SCIP_CONSDATA* consdata;
4819  SCIP_EXPR* expr;
4820  int c;
4821 
4822  assert(scip != NULL);
4823  assert(conshdlr != NULL);
4824 
4825  if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4826  return SCIP_OKAY;
4827 
4828  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4830 
4831  for( c = 0; c < nconss; ++c )
4832  {
4833  consdata = SCIPconsGetData(conss[c]);
4834  assert(consdata != NULL);
4835 
4836  /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4837  * i.e., skip children of sum that are variables
4838  */
4839  if( SCIPisExprSum(scip, consdata->expr) )
4840  {
4841  int i;
4842  SCIP_EXPR* child;
4843  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4844  {
4845  child = SCIPexprGetChildren(consdata->expr)[i];
4846 
4847  /* skip variable expression, as they correspond to a linear term */
4848  if( SCIPisExprVar(scip, child) )
4849  continue;
4850 
4851  for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4852  if( SCIPisExprVar(scip, expr) )
4853  {
4855  }
4856  }
4857  }
4858  else
4859  {
4860  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4861  if( SCIPisExprVar(scip, expr) )
4862  {
4864  }
4865  }
4866  }
4867 
4868  SCIPfreeExpriter(&it);
4869 
4870  return SCIP_OKAY;
4871 }
4872 
4873 /** simplifies expressions and replaces common subexpressions for a set of constraints
4874  * @todo put the constant to the constraint sides
4875  */
4876 static
4878  SCIP* scip, /**< SCIP data structure */
4879  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4880  SCIP_CONS** conss, /**< constraints */
4881  int nconss, /**< total number of constraints */
4882  SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4883  SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4884  int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4885  int* naddconss, /**< counter to add number of added constraints, or NULL */
4886  int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4887  )
4888 {
4889  SCIP_CONSHDLRDATA* conshdlrdata;
4890  SCIP_CONSDATA* consdata;
4891  int* nlockspos;
4892  int* nlocksneg;
4893  SCIP_Bool havechange;
4894  int i;
4895 
4896  assert(scip != NULL);
4897  assert(conshdlr != NULL);
4898  assert(conss != NULL);
4899  assert(nconss > 0);
4900  assert(infeasible != NULL);
4901 
4902  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4903  assert(conshdlrdata != NULL);
4904 
4905  /* update number of canonicalize calls */
4906  ++(conshdlrdata->ncanonicalizecalls);
4907 
4908  SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4909 
4910  *infeasible = FALSE;
4911 
4912  /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4913  havechange = conshdlrdata->ncanonicalizecalls == 1;
4914 
4915  /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4916  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4917 
4918  /* allocate memory for storing locks of each constraint */
4919  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4920  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4921 
4922  /* unlock all constraints */
4923  for( i = 0; i < nconss; ++i )
4924  {
4925  assert(conss[i] != NULL);
4926 
4927  consdata = SCIPconsGetData(conss[i]);
4928  assert(consdata != NULL);
4929 
4930  /* remember locks */
4931  nlockspos[i] = consdata->nlockspos;
4932  nlocksneg[i] = consdata->nlocksneg;
4933 
4934  /* remove locks */
4935  SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4936  assert(consdata->nlockspos == 0);
4937  assert(consdata->nlocksneg == 0);
4938  }
4939 
4940 #ifndef NDEBUG
4941  /* check whether all locks of each expression have been removed */
4942  for( i = 0; i < nconss; ++i )
4943  {
4944  SCIP_EXPR* expr;
4945  SCIP_EXPRITER* it;
4946 
4947  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4948 
4949  consdata = SCIPconsGetData(conss[i]);
4950  assert(consdata != NULL);
4951 
4952  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_RTOPOLOGIC, TRUE) );
4953  for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4954  {
4955  assert(expr != NULL);
4956  assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4957  assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4958  }
4959  SCIPfreeExpriter(&it);
4960  }
4961 #endif
4962 
4963  /* reformulate products of binary variables */
4964  if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4965  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4966  {
4967  int tmpnaddconss = 0;
4968  int tmpnchgcoefs = 0;
4969 
4970  /* call this function before simplification because expressions might not be simplified after reformulating
4971  * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4972  */
4973  SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4974 
4975  /* update counters */
4976  if( naddconss != NULL )
4977  *naddconss += tmpnaddconss;
4978  if( nchgcoefs != NULL )
4979  *nchgcoefs += tmpnchgcoefs;
4980 
4981  /* check whether at least one expression has changed */
4982  if( tmpnaddconss + tmpnchgcoefs > 0 )
4983  havechange = TRUE;
4984  }
4985 
4986  for( i = 0; i < nconss; ++i )
4987  {
4988  consdata = SCIPconsGetData(conss[i]);
4989  assert(consdata != NULL);
4990 
4991  /* call simplify for each expression */
4992  if( !consdata->issimplified && consdata->expr != NULL )
4993  {
4994  SCIP_EXPR* simplified;
4995  SCIP_Bool changed;
4996 
4997  changed = FALSE;
4998  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4999  consdata->issimplified = TRUE;
5000 
5001  if( changed )
5002  havechange = TRUE;
5003 
5004  /* 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").
5005  * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
5006  */
5007  if( simplified != consdata->expr )
5008  {
5009  assert(changed);
5010 
5011  /* release old expression */
5012  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
5013 
5014  /* store simplified expression */
5015  consdata->expr = simplified;
5016  }
5017  else
5018  {
5019  /* The simplify captures simplified in any case, also if nothing has changed.
5020  * Therefore, we have to release it here.
5021  */
5022  SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
5023  }
5024 
5025  if( *infeasible )
5026  break;
5027 
5028  /* scale constraint sides */
5029  SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
5030 
5031  if( changed )
5032  havechange = TRUE;
5033 
5034  /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
5035  if( SCIPisExprValue(scip, consdata->expr) )
5036  {
5037  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5038  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5039  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5040  {
5041  SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5042  SCIPdebugPrintCons(scip, conss[i], NULL);
5043  *infeasible = TRUE;
5044  break;
5045  }
5046  else
5047  {
5048  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5049  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5050  if( ndelconss != NULL )
5051  ++*ndelconss;
5052  havechange = TRUE;
5053  }
5054  }
5055  }
5056  }
5057 
5058  /* replace common subexpressions */
5059  if( havechange && !*infeasible )
5060  {
5061  SCIP_CONS** consssorted;
5062  SCIP_EXPR** rootexprs;
5063  SCIP_Bool replacedroot;
5064 
5065  SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5066  for( i = 0; i < nconss; ++i )
5067  rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5068 
5069  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5070 
5071  /* update pointer to root expr in constraints, if any has changed
5072  * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5073  */
5074  if( replacedroot )
5075  for( i = 0; i < nconss; ++i )
5076  SCIPconsGetData(conss[i])->expr = rootexprs[i];
5077 
5078  SCIPfreeBufferArray(scip, &rootexprs);
5079 
5080  /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5081  * been changed after simplification; now we completely recollect all variable expression and variable events
5082  */
5083 
5084  /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5085  * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5086  */
5087  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5088  SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5089 
5090  for( i = nconss-1; i >= 0; --i )
5091  {
5092  assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5093  if( SCIPconsIsDeleted(consssorted[i]) )
5094  continue;
5095 
5096  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5097  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5098  }
5099  for( i = 0; i < nconss; ++i )
5100  {
5101  if( SCIPconsIsDeleted(consssorted[i]) )
5102  continue;
5103 
5104  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5105  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5106  }
5107 
5108  SCIPfreeBufferArray(scip, &consssorted);
5109 
5110  /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5111  * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5112  * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5113  */
5114  SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5115  }
5116 
5117  /* restore locks */
5118  for( i = 0; i < nconss; ++i )
5119  {
5120  if( SCIPconsIsDeleted(conss[i]) )
5121  continue;
5122 
5123  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5124  }
5125 
5126  /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5127  * TODO can we skip this in presoltiming fast?
5128  */
5129  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5130  {
5131  /* reset one of the number of detections counter to count only current presolving round */
5132  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5133  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5134 
5135  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5136  }
5137 
5138  /* free allocated memory */
5139  SCIPfreeBufferArray(scip, &nlocksneg);
5140  SCIPfreeBufferArray(scip, &nlockspos);
5141 
5142  SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5143 
5144  return SCIP_OKAY;
5145 }
5146 
5147 /** merges constraints that have the same root expression */
5148 static
5150  SCIP* scip, /**< SCIP data structure */
5151  SCIP_CONS** conss, /**< constraints to process */
5152  int nconss, /**< number of constraints */
5153  SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5154  )
5155 {
5156  SCIP_HASHMAP* expr2cons;
5157  SCIP_Bool* updatelocks;
5158  int* nlockspos;
5159  int* nlocksneg;
5160  int c;
5161 
5162  assert(success != NULL);
5163 
5164  *success = FALSE;
5165 
5166  /* not enough constraints available */
5167  if( nconss <= 1 )
5168  return SCIP_OKAY;
5169 
5170  SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5171  SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5172  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5173  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5174 
5175  for( c = 0; c < nconss; ++c )
5176  {
5177  SCIP_CONSDATA* consdata;
5178 
5179  /* ignore deleted constraints */
5180  if( SCIPconsIsDeleted(conss[c]) )
5181  continue;
5182 
5183  consdata = SCIPconsGetData(conss[c]);
5184  assert(consdata != NULL);
5185 
5186  /* add expression to the hash map if not seen so far */
5187  if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5188  {
5189  SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5190  }
5191  else
5192  {
5193  SCIP_CONSDATA* imgconsdata;
5194  int idx;
5195 
5196  idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5197  assert(idx >= 0 && idx < nconss);
5198 
5199  imgconsdata = SCIPconsGetData(conss[idx]);
5200  assert(imgconsdata != NULL);
5201  assert(imgconsdata->expr == consdata->expr);
5202 
5203  SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5204  SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5205 
5206  /* check whether locks need to be updated */
5207  if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5208  || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5209  {
5210  nlockspos[idx] = imgconsdata->nlockspos;
5211  nlocksneg[idx] = imgconsdata->nlocksneg;
5212  SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5213  updatelocks[idx] = TRUE;
5214  }
5215 
5216  /* update constraint sides */
5217  imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5218  imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5219 
5220  /* delete constraint */
5221  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5222  *success = TRUE;
5223  }
5224  }
5225 
5226  /* restore locks of updated constraints */
5227  if( *success )
5228  {
5229  for( c = 0; c < nconss; ++c )
5230  {
5231  if( updatelocks[c] )
5232  {
5233  SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5234  }
5235  }
5236  }
5237 
5238  /* free memory */
5239  SCIPfreeBufferArray(scip, &nlocksneg);
5240  SCIPfreeBufferArray(scip, &nlockspos);
5241  SCIPfreeBufferArray(scip, &updatelocks);
5242  SCIPhashmapFree(&expr2cons);
5243 
5244  return SCIP_OKAY;
5245 }
5246 
5247 /** interval evaluation of variables as used in redundancy check
5248  *
5249  * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5250  */
5251 static
5252 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5253 { /*lint --e{715}*/
5254  SCIP_CONSHDLRDATA* conshdlrdata;
5255  SCIP_INTERVAL interval;
5256  SCIP_Real lb;
5257  SCIP_Real ub;
5258 
5259  assert(scip != NULL);
5260  assert(var != NULL);
5261 
5262  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5263  assert(conshdlrdata != NULL);
5264 
5265  if( conshdlrdata->globalbounds )
5266  {
5267  lb = SCIPvarGetLbGlobal(var);
5268  ub = SCIPvarGetUbGlobal(var);
5269  }
5270  else
5271  {
5272  lb = SCIPvarGetLbLocal(var);
5273  ub = SCIPvarGetUbLocal(var);
5274  }
5275  assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5276 
5277  /* relax variable bounds, if there are bounds and variable is not fixed
5278  * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5279  */
5280  if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5281  {
5282  if( !SCIPisInfinity(scip, -lb) )
5283  lb -= SCIPfeastol(scip);
5284 
5285  if( !SCIPisInfinity(scip, ub) )
5286  ub += SCIPfeastol(scip);
5287  }
5288 
5289  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5290  lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
5292  assert(lb <= ub);
5293 
5294  SCIPintervalSetBounds(&interval, lb, ub);
5295 
5296  return interval;
5297 }
5298 
5299 /** removes constraints that are always feasible or very simple
5300  *
5301  * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5302  * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5303  * might violate variable bounds by up to feastol, too.
5304  * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5305  *
5306  * Also removes constraints of the form lhs &le; variable &le; rhs.
5307  *
5308  * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5309  *
5310  * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5311  * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5312  * would appear as if the constraint is redundant.
5313  */
5314 static
5316  SCIP* scip, /**< SCIP data structure */
5317  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5318  SCIP_CONS** conss, /**< constraints to propagate */
5319  int nconss, /**< total number of constraints */
5320  SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5321  int* ndelconss, /**< buffer to add the number of deleted constraints */
5322  int* nchgbds /**< buffer to add the number of variable bound tightenings */
5323  )
5324 {
5325  SCIP_CONSHDLRDATA* conshdlrdata;
5326  SCIP_CONSDATA* consdata;
5327  SCIP_INTERVAL activity;
5328  SCIP_INTERVAL sides;
5329  int i;
5330 
5331  assert(scip != NULL);
5332  assert(conshdlr != NULL);
5333  assert(conss != NULL);
5334  assert(nconss >= 0);
5335  assert(cutoff != NULL);
5336  assert(ndelconss != NULL);
5337  assert(nchgbds != NULL);
5338 
5339  /* no constraints to check */
5340  if( nconss == 0 )
5341  return SCIP_OKAY;
5342 
5343  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5344  assert(conshdlrdata != NULL);
5345 
5346  /* increase curboundstag and set lastvaractivitymethodchange
5347  * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5348  * for the redundancy check differently than for domain propagation
5349  * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5350  */
5351  ++conshdlrdata->curboundstag;
5352  assert(conshdlrdata->curboundstag > 0);
5353  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5354  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5355  conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5356 
5357  SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5358 
5359  *cutoff = FALSE;
5360  for( i = 0; i < nconss; ++i )
5361  {
5362  if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5363  continue;
5364 
5365  consdata = SCIPconsGetData(conss[i]);
5366  assert(consdata != NULL);
5367 
5368  /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5369  if( SCIPisExprValue(scip, consdata->expr) )
5370  {
5371  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5372 
5373  if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5374  (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5375  {
5376  SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5377  *cutoff = TRUE;
5378 
5379  goto TERMINATE;
5380  }
5381 
5382  SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5383 
5384  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5385  ++*ndelconss;
5386 
5387  continue;
5388  }
5389 
5390  /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5391  if( SCIPisExprVar(scip, consdata->expr) )
5392  {
5393  SCIP_VAR* var;
5394  SCIP_Bool tightened;
5395 
5396  var = SCIPgetVarExprVar(consdata->expr);
5397  assert(var != NULL);
5398 
5399  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);
5400 
5401  /* ensure that variable bounds are within constraint sides */
5402  if( !SCIPisInfinity(scip, -consdata->lhs) )
5403  {
5404  SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5405 
5406  if( tightened )
5407  ++*nchgbds;
5408 
5409  if( *cutoff )
5410  goto TERMINATE;
5411  }
5412 
5413  if( !SCIPisInfinity(scip, consdata->rhs) )
5414  {
5415  SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5416 
5417  if( tightened )
5418  ++*nchgbds;
5419 
5420  if( *cutoff )
5421  goto TERMINATE;
5422  }
5423 
5424  /* delete the (now) redundant constraint locally */
5425  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5426  ++*ndelconss;
5427 
5428  continue;
5429  }
5430 
5431  /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5432  * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5433  * variable bounds by up to feastol
5434  * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5435  */
5436  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5437  SCIPdebugPrintCons(scip, conss[i], NULL);
5438 
5439  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5440  assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5441 
5442  /* it is unlikely that we detect infeasibility by doing forward propagation */
5443  if( *cutoff )
5444  {
5445  SCIPdebugMsg(scip, " -> cutoff\n");
5446  goto TERMINATE;
5447  }
5448 
5449  assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5450  activity = SCIPexprGetActivity(consdata->expr);
5451 
5452  /* relax sides by feastol
5453  * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5454  */
5455  SCIPintervalSetBounds(&sides,
5456  SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5457  SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5458 
5459  if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5460  {
5461  SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5462 
5463  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5464  ++*ndelconss;
5465 
5466  continue;
5467  }
5468 
5469  SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5470  }
5471 
5472 TERMINATE:
5473  /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5474  ++conshdlrdata->curboundstag;
5475  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5476  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5477  conshdlrdata->intevalvar = intEvalVarBoundTightening;
5478 
5479  return SCIP_OKAY;
5480 }
5481 
5482 /** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5483 static
5485  SCIP* scip, /**< SCIP data structure */
5486  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5487  SCIP_CONS* cons, /**< source constraint to try to convert */
5488  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5489  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5490  int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5491  )
5492 {
5493  SCIP_CONSHDLRDATA* conshdlrdata;
5494  SCIP_CONSDATA* consdata;
5495  SCIP_CONS** upgdconss;
5496  int upgdconsssize;
5497  int nupgdconss_;
5498  int i;
5499 
5500  assert(scip != NULL);
5501  assert(conshdlr != NULL);
5502  assert(cons != NULL);
5503  assert(!SCIPconsIsModifiable(cons));
5504  assert(upgraded != NULL);
5505  assert(nupgdconss != NULL);
5506  assert(naddconss != NULL);
5507 
5508  *upgraded = FALSE;
5509 
5510  nupgdconss_ = 0;
5511 
5512  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5513  assert(conshdlrdata != NULL);
5514 
5515  /* if there are no upgrade methods, we can stop */
5516  if( conshdlrdata->nconsupgrades == 0 )
5517  return SCIP_OKAY;
5518 
5519  upgdconsssize = 2;
5520  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5521 
5522  /* call the upgrading methods */
5523  SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5524  SCIPdebugPrintCons(scip, cons, NULL);
5525 
5526  consdata = SCIPconsGetData(cons);
5527  assert(consdata != NULL);
5528 
5529  /* try all upgrading methods in priority order in case the upgrading step is enable */
5530  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5531  {
5532  if( !conshdlrdata->consupgrades[i]->active )
5533  continue;
5534 
5535  assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5536 
5537  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5538 
5539  while( nupgdconss_ < 0 )
5540  {
5541  /* upgrade function requires more memory: resize upgdconss and call again */
5542  assert(-nupgdconss_ > upgdconsssize);
5543  upgdconsssize = -nupgdconss_;
5544  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5545 
5546  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5547 
5548  assert(nupgdconss_ != 0);
5549  }
5550 
5551  if( nupgdconss_ > 0 )
5552  {
5553  /* got upgrade */
5554  int j;
5555 
5556  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5557 
5558  /* add the upgraded constraints to the problem and forget them */
5559  for( j = 0; j < nupgdconss_; ++j )
5560  {
5561  SCIPdebugMsgPrint(scip, "\t");
5562  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5563 
5564  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5565  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5566  }
5567 
5568  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5569  *nupgdconss += 1;
5570  *naddconss += nupgdconss_ - 1;
5571  *upgraded = TRUE;
5572 
5573  /* delete upgraded constraint */
5574  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5575  SCIP_CALL( SCIPdelCons(scip, cons) );
5576 
5577  break;
5578  }
5579  }
5580 
5581  SCIPfreeBufferArray(scip, &upgdconss);
5582 
5583  return SCIP_OKAY;
5584 }
5585 
5586 /** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5587  * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5588  * variable bounds, and is not binary
5589  */
5590 static
5592  SCIP* scip, /**< SCIP data structure */
5593  SCIP_EXPR* expr /**< variable expression */
5594  )
5595 {
5596  SCIP_VAR* var;
5597  SCIP_EXPR_OWNERDATA* ownerdata;
5598 
5599  assert(SCIPisExprVar(scip, expr));
5600 
5601  var = SCIPgetVarExprVar(expr);
5602  assert(var != NULL);
5603 
5604  ownerdata = SCIPexprGetOwnerData(expr);
5605  assert(ownerdata != NULL);
5606 
5607  return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5608  && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5609  && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5610  && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5612  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5613 }
5614 
5615 /** removes all variable expressions that are contained in a given expression from a hash map */
5616 static
5618  SCIP* scip, /**< SCIP data structure */
5619  SCIP_EXPR* expr, /**< expression */
5620  SCIP_EXPRITER* it, /**< expression iterator */
5621  SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5622  )
5623 {
5624  SCIP_EXPR* e;
5625 
5626  for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5627  {
5628  if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5629  {
5630  SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5631  }
5632  }
5633 
5634  return SCIP_OKAY;
5635 }
5636 
5637 /** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5638  * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5639  *
5640  * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5641  * Otherwise, a bound disjunction constraint is added.
5642  *
5643  * @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
5644  * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5645  * 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
5646  * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5647  * @todo reduction should also be applicable if variable appears in the objective with the right sign (sign such that opt is at boundary)
5648  */
5649 static
5651  SCIP* scip, /**< SCIP data structure */
5652  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5653  SCIP_CONS* cons, /**< nonlinear constraint */
5654  int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5655  int* naddconss, /**< pointer to store the total number of added constraints */
5656  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5657  )
5658 {
5659  SCIP_CONSHDLRDATA* conshdlrdata;
5660  SCIP_CONSDATA* consdata;
5661  SCIP_EXPR** singlelocked;
5662  SCIP_HASHMAP* exprcands;
5663  SCIP_Bool hasbounddisj;
5664  SCIP_Bool haslhs;
5665  SCIP_Bool hasrhs;
5666  int nsinglelocked = 0;
5667  int i;
5668 
5669  assert(conshdlr != NULL);
5670  assert(cons != NULL);
5671  assert(nchgvartypes != NULL);
5672  assert(naddconss != NULL);
5673  assert(infeasible != NULL);
5674 
5675  *nchgvartypes = 0;
5676  *naddconss = 0;
5677  *infeasible = FALSE;
5678 
5679  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5680  assert(conshdlrdata != NULL);
5681  consdata = SCIPconsGetData(cons);
5682  assert(consdata != NULL);
5683 
5684  /* only consider constraints with one finite side */
5685  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5686  return SCIP_OKAY;
5687 
5688  /* only consider sum expressions */
5689  if( !SCIPisExprSum(scip, consdata->expr) )
5690  return SCIP_OKAY;
5691 
5692  /* remember which side is finite */
5693  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5694  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5695 
5696  /* allocate memory */
5697  SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5698  SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5699 
5700  /* check all variable expressions for single locked variables */
5701  for( i = 0; i < consdata->nvarexprs; ++i )
5702  {
5703  assert(consdata->varexprs[i] != NULL);
5704 
5705  if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5706  {
5707  SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5708  singlelocked[nsinglelocked++] = consdata->varexprs[i];
5709  }
5710  }
5711  SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5712 
5713  if( nsinglelocked > 0 )
5714  {
5715  SCIP_EXPR** children;
5716  SCIP_EXPRITER* it;
5717  int nchildren;
5718 
5719  children = SCIPexprGetChildren(consdata->expr);
5720  nchildren = SCIPexprGetNChildren(consdata->expr);
5721 
5722  /* create iterator */
5723  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
5726 
5727  for( i = 0; i < nchildren; ++i )
5728  {
5729  SCIP_EXPR* child;
5730  SCIP_Real coef;
5731 
5732  child = children[i];
5733  assert(child != NULL);
5734  coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5735 
5736  /* ignore linear terms */
5737  if( SCIPisExprVar(scip, child) )
5738  continue;
5739 
5740  /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5741  * expression that represents f_j and remove each variable expression from exprcands
5742  */
5743  else if( SCIPisExprProduct(scip, child) )
5744  {
5745  int j;
5746 
5747  for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5748  {
5749  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5750 
5751  if( !SCIPisExprVar(scip, grandchild) )
5752  {
5753  /* mark all variable expressions that are contained in the expression */
5754  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5755  }
5756  }
5757  }
5758  /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5759  * for an integer k >= 1
5760  */
5761  else if( SCIPisExprPower(scip, child) )
5762  {
5763  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5764  SCIP_Real exponent = SCIPgetExponentExprPow(child);
5765  SCIP_Bool valid;
5766 
5767  /* check for even integral exponent */
5768  valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5769 
5770  if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5771  {
5772  /* mark all variable expressions that are contained in the expression */
5773  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5774  }
5775  }
5776  /* all other cases cannot be handled */
5777  else
5778  {
5779  /* mark all variable expressions that are contained in the expression */
5780  SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5781  }
5782  }
5783 
5784  /* free expression iterator */
5785  SCIPfreeExpriter(&it);
5786  }
5787 
5788  /* check whether the bound disjunction constraint handler is available */
5789  hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5790 
5791  /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5792  for( i = 0; i < nsinglelocked; ++i )
5793  {
5794  /* only consider expressions that are still contained in the exprcands map */
5795  if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5796  {
5797  SCIP_CONS* newcons;
5798  SCIP_VAR* vars[2];
5799  SCIP_BOUNDTYPE boundtypes[2];
5800  SCIP_Real bounds[2];
5801  char name[SCIP_MAXSTRLEN];
5802  SCIP_VAR* var;
5803 
5804  var = SCIPgetVarExprVar(singlelocked[i]);
5805  assert(var != NULL);
5806  SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5808 
5809  /* try to change the variable type to binary */
5810  if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5811  {
5812  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5813  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5814  ++(*nchgvartypes);
5815 
5816  if( *infeasible )
5817  {
5818  SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5819  break;
5820  }
5821  }
5822  /* add bound disjunction constraint if bounds of the variable are finite */
5823  else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5824  {
5825  vars[0] = var;
5826  vars[1] = var;
5827  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5828  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5829  bounds[0] = SCIPvarGetUbGlobal(var);
5830  bounds[1] = SCIPvarGetLbGlobal(var);
5831 
5832  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5833 
5834  /* create, add, and release bound disjunction constraint */
5835  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5836  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5837  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5838  SCIP_CALL( SCIPaddCons(scip, newcons) );
5839  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5840  ++(*naddconss);
5841  }
5842  }
5843  }
5844 
5845  /* free memory */
5846  SCIPfreeBufferArray(scip, &singlelocked);
5847  SCIPhashmapFree(&exprcands);
5848 
5849  return SCIP_OKAY;
5850 }
5851 
5852 /** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5853 static
5855  SCIP* scip, /**< SCIP data structure */
5856  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5857  SCIP_CONS** conss, /**< nonlinear constraints */
5858  int nconss, /**< total number of nonlinear constraints */
5859  int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5860  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5861  )
5862 {
5863  int c;
5864 
5865  assert(scip != NULL);
5866  assert(conshdlr != NULL);
5867  assert(conss != NULL || nconss == 0);
5868  assert(nchgvartypes != NULL);
5869  assert(infeasible != NULL);
5870 
5871  *infeasible = FALSE;
5872 
5873  /* nothing can be done if there are no binary and integer variables available */
5874  if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5875  return SCIP_OKAY;
5876 
5877  /* no continuous var can be made implicit-integer if there are no continuous variables */
5878  if( SCIPgetNContVars(scip) == 0 )
5879  return SCIP_OKAY;
5880 
5881  for( c = 0; c < nconss; ++c )
5882  {
5883  SCIP_CONSDATA* consdata;
5884  SCIP_EXPR** children;
5885  int nchildren;
5886  SCIP_Real* coefs;
5887  SCIP_EXPR* cand = NULL;
5888  SCIP_Real candcoef = 0.0;
5889  int i;
5890 
5891  assert(conss != NULL && conss[c] != NULL);
5892 
5893  consdata = SCIPconsGetData(conss[c]);
5894  assert(consdata != NULL);
5895 
5896  /* the constraint must be an equality constraint */
5897  if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5898  continue;
5899 
5900  /* the root expression needs to be a sum expression */
5901  if( !SCIPisExprSum(scip, consdata->expr) )
5902  continue;
5903 
5904  children = SCIPexprGetChildren(consdata->expr);
5905  nchildren = SCIPexprGetNChildren(consdata->expr);
5906 
5907  /* the sum expression must have at least two children
5908  * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5909  */
5910  if( nchildren <= 1 )
5911  continue;
5912 
5913  coefs = SCIPgetCoefsExprSum(consdata->expr);
5914 
5915  /* find first continuous variable and get value of its coefficient */
5916  for( i = 0; i < nchildren; ++i )
5917  {
5918  if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5919  continue;
5920 
5921  candcoef = coefs[i];
5922  assert(candcoef != 0.0);
5923 
5924  /* lhs/rhs - constant divided by candcoef must be integral
5925  * if not, break with cand == NULL, so give up
5926  */
5927  if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5928  cand = children[i];
5929 
5930  break;
5931  }
5932 
5933  /* no suitable continuous variable found */
5934  if( cand == NULL )
5935  continue;
5936 
5937  /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5938  for( i = 0; i < nchildren; ++i )
5939  {
5940  if( children[i] == cand )
5941  continue;
5942 
5943  /* child i must be integral */
5944  if( !SCIPexprIsIntegral(children[i]) )
5945  {
5946  cand = NULL;
5947  break;
5948  }
5949 
5950  /* coefficient of child i must be integral if diving by candcoef */
5951  if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5952  {
5953  cand = NULL;
5954  break;
5955  }
5956  }
5957 
5958  if( cand == NULL )
5959  continue;
5960 
5961  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5963 
5964  /* change variable type */
5965  SCIP_CALL( SCIPchgVarType(scip, SCIPgetVarExprVar(cand), SCIP_VARTYPE_IMPLINT, infeasible) );
5966 
5967  if( *infeasible )
5968  return SCIP_OKAY;
5969 
5970  /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5972  }
5973 
5974  return SCIP_OKAY;
5975 }
5976 
5977 /** creates auxiliary variable for a given expression
5978  *
5979  * @note for a variable expression it does nothing
5980  * @note this function can only be called in stage SCIP_STAGE_SOLVING
5981  */
5982 static
5984  SCIP* scip, /**< SCIP data structure */
5985  SCIP_EXPR* expr /**< expression */
5986  )
5987 {
5988  SCIP_EXPR_OWNERDATA* ownerdata;
5989  SCIP_CONSHDLRDATA* conshdlrdata;
5990  SCIP_VARTYPE vartype;
5991  SCIP_INTERVAL activity;
5992  char name[SCIP_MAXSTRLEN];
5993 
5994  assert(scip != NULL);
5995  assert(expr != NULL);
5996 
5997  ownerdata = SCIPexprGetOwnerData(expr);
5998  assert(ownerdata != NULL);
5999  assert(ownerdata->nauxvaruses > 0);
6000 
6001  /* if we already have auxvar, then do nothing */
6002  if( ownerdata->auxvar != NULL )
6003  return SCIP_OKAY;
6004 
6005  /* if expression is a variable-expression, then do nothing */
6006  if( SCIPisExprVar(scip, expr) )
6007  return SCIP_OKAY;
6008 
6009  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
6010  {
6011  SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
6012  return SCIP_INVALIDCALL;
6013  }
6014 
6015  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
6016  assert(conshdlrdata != NULL);
6017  assert(conshdlrdata->auxvarid >= 0);
6018 
6019  /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
6020  * but it usually indicates a missing simplify
6021  * if we find situations where we need to have an auxvar for a constant, then remove this assert
6022  */
6023  assert(!SCIPisExprValue(scip, expr));
6024 
6025  /* create and capture auxiliary variable */
6026  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
6027  ++conshdlrdata->auxvarid;
6028 
6029  /* type of auxiliary variable depends on integrality information of the expression */
6031 
6032  /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
6033  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
6034  {
6035  activity = SCIPexprGetActivity(expr);
6036  /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
6037  * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
6038  * and abort in debug mode only
6039  */
6041  {
6042  SCIPABORT();
6044  }
6045  }
6046  else
6048 
6049  /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
6050  * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
6051  */
6052  if( SCIPgetDepth(scip) == 0 )
6053  {
6054  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
6055  }
6056  else
6057  {
6058  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
6059  }
6060 
6061  /* mark the auxiliary variable to be added for the relaxation only
6062  * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
6063  * or to copy the variable to a subscip
6064  */
6065  SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
6066 
6067  SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
6068 
6069  SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
6070 
6071  /* add variable locks in both directions
6072  * TODO should be sufficient to lock only according to expr->nlockspos/neg,
6073  * but then we need to also update the auxvars locks when the expr locks change
6074  */
6075  SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
6076 
6077 #ifdef WITH_DEBUG_SOLUTION
6078  if( SCIPdebugIsMainscip(scip) )
6079  {
6080  /* store debug solution value of auxiliary variable
6081  * assumes that expression has been evaluated in debug solution before
6082  */
6083  SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
6084  }
6085 #endif
6086 
6087  if( SCIPgetDepth(scip) > 0 )
6088  {
6089  /* initialize local bounds to (locally valid) activity */
6090  SCIP_Bool cutoff;
6091  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
6092  assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
6093  }
6094 
6095  return SCIP_OKAY;
6096 }
6097 
6098 /** initializes separation for constraint
6099  *
6100  * - ensures that activities are up to date in all expressions
6101  * - creates auxiliary variables where required
6102  * - calls propExprDomains() to possibly tighten auxvar bounds
6103  * - calls separation initialization callback of nlhdlrs
6104  */
6105 static
6107  SCIP* scip, /**< SCIP data structure */
6108  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6109  SCIP_CONS** conss, /**< constraints */
6110  int nconss, /**< number of constraints */
6111  SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
6112  )
6113 {
6114  SCIP_CONSDATA* consdata;
6115  SCIP_CONSHDLRDATA* conshdlrdata;
6116  SCIP_EXPRITER* it;
6117  SCIP_EXPR* expr;
6118  SCIP_RESULT result;
6119  SCIP_VAR* auxvar;
6120  int nreductions = 0;
6121  int c, e;
6122 
6123  assert(scip != NULL);
6124  assert(conshdlr != NULL);
6125  assert(conss != NULL || nconss == 0);
6126  assert(nconss >= 0);
6127  assert(infeasible != NULL);
6128 
6129  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6130  assert(conshdlrdata != NULL);
6131 
6132  /* start with new propbounds (just to be sure, should not be needed) */
6133  ++conshdlrdata->curpropboundstag;
6134 
6135  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6137 
6138  /* first ensure activities are up to date and create auxvars */
6139  *infeasible = FALSE;
6140  for( c = 0; c < nconss; ++c )
6141  {
6142  assert(conss != NULL);
6143  assert(conss[c] != NULL);
6144 
6145  consdata = SCIPconsGetData(conss[c]);
6146  assert(consdata != NULL);
6147  assert(consdata->expr != NULL);
6148 
6149 #ifdef WITH_DEBUG_SOLUTION
6150  if( SCIPdebugIsMainscip(scip) )
6151  {
6152  SCIP_SOL* debugsol;
6153 
6154  SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6155 
6156  if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6157  {
6158  /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6159  * in createAuxVar()
6160  */
6161  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6162  }
6163  }
6164 #endif
6165 
6166  /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6167  SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6168 
6169  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6170  {
6171  if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6172  {
6173  SCIP_CALL( createAuxVar(scip, expr) );
6174  }
6175  }
6176 
6177  auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6178  if( auxvar != NULL )
6179  {
6180  SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6181  SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6182  /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6183  SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6184  if( *infeasible )
6185  {
6186  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6187  break;
6188  }
6189 
6190  SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6191  if( *infeasible )
6192  {
6193  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6194  break;
6195  }
6196  }
6197  }
6198 
6199  /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6200  * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6201  * (e.g., log(x*y), which becomes log(w), w=x*y
6202  * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6203  */
6204  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6205  if( result == SCIP_CUTOFF )
6206  *infeasible = TRUE;
6207 
6208  /* now call initsepa of nlhdlrs
6209  * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6210  * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6211  */
6213  for( c = 0; c < nconss && !*infeasible; ++c )
6214  {
6215  assert(conss != NULL);
6216  assert(conss[c] != NULL);
6217 
6218  consdata = SCIPconsGetData(conss[c]);
6219  assert(consdata != NULL);
6220  assert(consdata->expr != NULL);
6221 
6222  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6223  {
6224  SCIP_EXPR_OWNERDATA* ownerdata;
6225 
6226  ownerdata = SCIPexprGetOwnerData(expr);
6227  assert(ownerdata != NULL);
6228 
6229  if( ownerdata->nauxvaruses == 0 )
6230  continue;
6231 
6232  for( e = 0; e < ownerdata->nenfos; ++e )
6233  {
6234  SCIP_NLHDLR* nlhdlr;
6235  SCIP_Bool underestimate;
6236  SCIP_Bool overestimate;
6237  assert(ownerdata->enfos[e] != NULL);
6238 
6239  /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6240  * which participated in a previous initSepa() call
6241  */
6242  if( ownerdata->enfos[e]->issepainit )
6243  continue;
6244 
6245  /* only call initsepa if it will actually separate */
6246  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6247  continue;
6248 
6249  nlhdlr = ownerdata->enfos[e]->nlhdlr;
6250  assert(nlhdlr != NULL);
6251 
6252  /* only init sepa if there is an initsepa callback */
6253  if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6254  continue;
6255 
6256  /* check whether expression needs to be under- or overestimated */
6257  overestimate = ownerdata->nlocksneg > 0;
6258  underestimate = ownerdata->nlockspos > 0;
6259  assert(underestimate || overestimate);
6260 
6261  SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6262 
6263  /* call the separation initialization callback of the nonlinear handler */
6264  SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6265  ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6266  ownerdata->enfos[e]->issepainit = TRUE;
6267 
6268  if( *infeasible )
6269  {
6270  /* stop everything if we detected infeasibility */
6271  SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6272  break;
6273  }
6274  }
6275  }
6276  }
6277 
6278  SCIPfreeExpriter(&it);
6279 
6280  return SCIP_OKAY;
6281 }
6282 
6283 /** returns whether we are ok to branch on auxiliary variables
6284  *
6285  * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6286  */
6287 static
6289  SCIP* scip, /**< SCIP data structure */
6290  SCIP_CONSHDLR* conshdlr /**< constraint handler */
6291  )
6292 {
6293  SCIP_CONSHDLRDATA* conshdlrdata;
6294 
6295  assert(conshdlr != NULL);
6296 
6297  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6298  assert(conshdlrdata != NULL);
6299 
6300  return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6301 }
6302 
6303 /** gets weight of variable when splitting violation score onto several variables in an expression */
6304 static
6306  SCIP* scip, /**< SCIP data structure */
6307  SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6308  SCIP_VAR* var, /**< variable */
6309  SCIP_SOL* sol /**< current solution */
6310  )
6311 {
6312  SCIP_CONSHDLRDATA* conshdlrdata;
6313 
6314  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6315  assert(conshdlrdata != NULL);
6316 
6317  switch( conshdlrdata->branchviolsplit )
6318  {
6319  case 'u' : /* uniform: everyone gets the same score */
6320  return 1.0;
6321 
6322  case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6323  {
6324  SCIP_Real weight;
6325  weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6326  return MAX(0.05, weight);
6327  }
6328 
6329  case 'd' : /* domain width */
6330  return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6331 
6332  case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6333  {
6334  SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6335  assert(width > 0.0);
6336  if( width > 10.0 )
6337  return 10.0*log10(width);
6338  if( width < 0.1 )
6339  return 0.1/(-log10(width));
6340  return width;
6341  }
6342 
6343  default :
6344  SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6345  SCIPABORT();
6346  return SCIP_INVALID;
6347  }
6348 }
6349 
6350 /** adds violation-branching score to a set of expressions, thereby distributing the score
6351  *
6352  * Each expression must either be a variable expression or have an aux-variable.
6353  *
6354  * If unbounded variables are present, each unbounded var gets an even score.
6355  * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6356  */
6357 static
6358 void addExprsViolScore(
6359  SCIP* scip, /**< SCIP data structure */
6360  SCIP_EXPR** exprs, /**< expressions where to add branching score */
6361  int nexprs, /**< number of expressions */
6362  SCIP_Real violscore, /**< violation-branching score to add to expression */
6363  SCIP_SOL* sol, /**< current solution */
6364  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6365  )
6366 {
6367  SCIP_CONSHDLR* conshdlr;
6368  SCIP_VAR* var;
6369  SCIP_Real weight;
6370  SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6371  int nunbounded = 0; /* number of candidates with unbounded domain */
6372  int i;
6373 
6374  assert(exprs != NULL);
6375  assert(nexprs > 0);
6376  assert(success != NULL);
6377 
6378  if( nexprs == 1 )
6379  {
6380  SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6381  SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6383  *success = TRUE;
6384  return;
6385  }
6386 
6387  conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6388 
6389  for( i = 0; i < nexprs; ++i )
6390  {
6391  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6392  assert(var != NULL);
6393 
6394  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6395  ++nunbounded;
6396  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6397  weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6398  }
6399 
6400  *success = FALSE;
6401  for( i = 0; i < nexprs; ++i )
6402  {
6403  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6404  assert(var != NULL);
6405 
6406  if( nunbounded > 0 )
6407  {
6408  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6409  {
6410  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6411  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6412  100.0/nunbounded, violscore,
6414  *success = TRUE;
6415  }
6416  }
6417  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6418  {
6419  assert(weightsum > 0.0);
6420 
6421  weight = getViolSplitWeight(scip, conshdlr, var, sol);
6422  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6423  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6424  100*weight / weightsum, violscore,
6426  *success = TRUE;
6427  }
6428  else
6429  {
6430  SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6432  }
6433  }
6434 }
6435 
6436 /** adds violation-branching score to children of expression for given auxiliary variables
6437  *
6438  * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6439  * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6440  *
6441  * @note This method may modify the given auxvars array by means of sorting.
6442  */
6443 static
6445  SCIP* scip, /**< SCIP data structure */
6446  SCIP_EXPR* expr, /**< expression where to start searching */
6447  SCIP_Real violscore, /**< violation score to add to expression */
6448  SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6449  int nauxvars, /**< number of auxiliary variables */
6450  SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6451  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6452  )
6453 {
6454  SCIP_EXPRITER* it;
6455  SCIP_VAR* auxvar;
6456  SCIP_EXPR** exprs;
6457  int nexprs;
6458  int pos;
6459 
6460  assert(scip != NULL);
6461  assert(expr != NULL);
6462  assert(auxvars != NULL);
6463  assert(success != NULL);
6464 
6465  /* sort variables to make lookup below faster */
6466  SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6467 
6468  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6470 
6471  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6472  nexprs = 0;
6473 
6474  for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6475  {
6476  auxvar = SCIPgetExprAuxVarNonlinear(expr);
6477  if( auxvar == NULL )
6478  continue;
6479 
6480  /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6481  if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6482  {
6483  assert(auxvars[pos] == auxvar);
6484 
6485  SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6486  exprs[nexprs++] = expr;
6487 
6488  if( nexprs == nauxvars )
6489  break;
6490  }
6491  }
6492 
6493  SCIPfreeExpriter(&it);
6494 
6495  if( nexprs > 0 )
6496  {
6497  SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6498  }
6499  else
6500  *success = FALSE;
6501 
6502  SCIPfreeBufferArray(scip, &exprs);
6503 
6504  return SCIP_OKAY;
6505 }
6506 
6507 /** registers all unfixed variables in violated constraints as branching candidates */
6508 static
6510  SCIP* scip, /**< SCIP data structure */
6511  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6512  SCIP_CONS** conss, /**< constraints */
6513  int nconss, /**< number of constraints */
6514  int* nnotify /**< counter for number of notifications performed */
6515  )
6516 {
6517  SCIP_CONSDATA* consdata;
6518  SCIP_VAR* var;
6519  int c;
6520  int i;
6521 
6522  assert(conshdlr != NULL);
6523  assert(conss != NULL || nconss == 0);
6524  assert(nnotify != NULL);
6525 
6526  *nnotify = 0;
6527 
6528  for( c = 0; c < nconss; ++c )
6529  {
6530  assert(conss != NULL && conss[c] != NULL);
6531 
6532  consdata = SCIPconsGetData(conss[c]);
6533  assert(consdata != NULL);
6534 
6535  /* consider only violated constraints */
6536  if( !isConsViolated(scip, conss[c]) )
6537  continue;
6538 
6539  /* register all variables that have not been fixed yet */
6540  assert(consdata->varexprs != NULL);
6541  for( i = 0; i < consdata->nvarexprs; ++i )
6542  {
6543  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6544  assert(var != NULL);
6545 
6546  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6547  {
6549  ++(*nnotify);
6550  }
6551  }
6552  }
6553 
6554  return SCIP_OKAY;
6555 }
6556 
6557 /** registers all variables in violated constraints with branching scores as external branching candidates */
6558 static
6560  SCIP* scip, /**< SCIP data structure */
6561  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6562  SCIP_CONS** conss, /**< constraints */
6563  int nconss, /**< number of constraints */
6564  SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6565  )
6566 {
6567  SCIP_CONSDATA* consdata;
6568  SCIP_EXPRITER* it = NULL;
6569  int c;
6570 
6571  assert(conshdlr != NULL);
6572  assert(success != NULL);
6573 
6574  *success = FALSE;
6575 
6576  if( branchAuxNonlinear(scip, conshdlr) )
6577  {
6578  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6580  }
6581 
6582  /* register external branching candidates */
6583  for( c = 0; c < nconss; ++c )
6584  {
6585  assert(conss != NULL && conss[c] != NULL);
6586 
6587  consdata = SCIPconsGetData(conss[c]);
6588  assert(consdata != NULL);
6589  assert(consdata->varexprs != NULL);
6590 
6591  /* consider only violated constraints */
6592  if( !isConsViolated(scip, conss[c]) )
6593  continue;
6594 
6595  if( !branchAuxNonlinear(scip, conshdlr) )
6596  {
6597  int i;
6598 
6599  /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6600  * only, so we can loop over variable expressions
6601  */
6602  for( i = 0; i < consdata->nvarexprs; ++i )
6603  {
6604  SCIP_Real violscore;
6605  SCIP_Real lb;
6606  SCIP_Real ub;
6607  SCIP_VAR* var;
6608 
6609  violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6610 
6611  /* skip variable expressions that do not have a violation score */
6612  if( violscore == 0.0 )
6613  continue;
6614 
6615  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6616  assert(var != NULL);
6617 
6618  lb = SCIPvarGetLbLocal(var);
6619  ub = SCIPvarGetUbLocal(var);
6620 
6621  /* consider variable for branching if it has not been fixed yet */
6622  if( !SCIPisEQ(scip, lb, ub) )
6623  {
6624  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6625  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6626  *success = TRUE;
6627  }
6628  else
6629  {
6630  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6631  }
6632 
6633  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6634  * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6635  */
6636  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6637  }
6638  }
6639  else
6640  {
6641  SCIP_EXPR* expr;
6642  SCIP_VAR* var;
6643  SCIP_Real lb;
6644  SCIP_Real ub;
6645  SCIP_Real violscore;
6646 
6647  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6648  {
6649  violscore = SCIPgetExprViolScoreNonlinear(expr);
6650  if( violscore == 0.0 )
6651  continue;
6652 
6653  /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6654  * variable, so this expression should either be an original variable or have an auxiliary variable
6655  */
6656  var = SCIPgetExprAuxVarNonlinear(expr);
6657  assert(var != NULL);
6658 
6659  lb = SCIPvarGetLbLocal(var);
6660  ub = SCIPvarGetUbLocal(var);
6661 
6662  /* consider variable for branching if it has not been fixed yet */
6663  if( !SCIPisEQ(scip, lb, ub) )
6664  {
6665  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6666 
6667  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6668  *success = TRUE;
6669  }
6670  else
6671  {
6672  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6673  }
6674  }
6675  }
6676  }
6677 
6678  if( it != NULL )
6679  SCIPfreeExpriter(&it);
6680 
6681  return SCIP_OKAY;
6682 }
6683 
6684 /** collect branching candidates from violated constraints
6685  *
6686  * Fills array with expressions that serve as branching candidates.
6687  * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6688  * branching candidate.
6689  *
6690  * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6691  * through variable-expressions only.
6692  */
6693 static
6695  SCIP* scip, /**< SCIP data structure */
6696  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6697  SCIP_CONS** conss, /**< constraints to process */
6698  int nconss, /**< number of constraints */
6699  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6700  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6701  SCIP_Longint soltag, /**< tag of solution */
6702  BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6703  int* ncands /**< number of candidates found */
6704  )
6705 {
6706  SCIP_CONSHDLRDATA* conshdlrdata;
6707  SCIP_CONSDATA* consdata;
6708  SCIP_EXPRITER* it = NULL;
6709  int c;
6710  int attempt;
6711  SCIP_VAR* var;
6712 
6713  assert(scip != NULL);
6714  assert(conshdlr != NULL);
6715  assert(cands != NULL);
6716  assert(ncands != NULL);
6717 
6718  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6719  assert(conshdlrdata != NULL);
6720 
6721  if( branchAuxNonlinear(scip, conshdlr) )
6722  {
6723  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6725  }
6726 
6727  *ncands = 0;
6728  for( attempt = 0; attempt < 2; ++attempt )
6729  {
6730  /* collect branching candidates from violated constraints
6731  * in the first attempt, consider only constraints with large violation
6732  * in the second attempt, consider all remaining violated constraints
6733  */
6734  for( c = 0; c < nconss; ++c )
6735  {
6736  SCIP_Real consviol;
6737 
6738  assert(conss != NULL && conss[c] != NULL);
6739 
6740  /* consider only violated constraints */
6741  if( !isConsViolated(scip, conss[c]) )
6742  continue;
6743 
6744  consdata = SCIPconsGetData(conss[c]);
6745  assert(consdata != NULL);
6746  assert(consdata->varexprs != NULL);
6747 
6748  SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6749 
6750  if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6751  continue;
6752  else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6753  continue;
6754 
6755  if( !branchAuxNonlinear(scip, conshdlr) )
6756  {
6757  int i;
6758 
6759  /* if not branching on auxvars, then violation-branching scores will be available for original variables
6760  * only, so we can loop over variable expressions
6761  * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6762  * variable, therefore we invalidate the score of a variable after processing it.
6763  */
6764  for( i = 0; i < consdata->nvarexprs; ++i )
6765  {
6766  SCIP_Real lb;
6767  SCIP_Real ub;
6768 
6769  /* skip variable expressions that do not have a valid violation score */
6770  if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6771  continue;
6772 
6773  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6774  assert(var != NULL);
6775 
6776  lb = SCIPvarGetLbLocal(var);
6777  ub = SCIPvarGetUbLocal(var);
6778 
6779  /* skip already fixed variable */
6780  if( SCIPisEQ(scip, lb, ub) )
6781  {
6782  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6783  continue;
6784  }
6785 
6786  assert(*ncands + 1 < SCIPgetNVars(scip));
6787  cands[*ncands].expr = consdata->varexprs[i];
6788  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6789  ++(*ncands);
6790 
6791  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6792  * several times as external branching candidate */
6793  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6794  }
6795  }
6796  else
6797  {
6798  SCIP_EXPR* expr;
6799  SCIP_Real lb;
6800  SCIP_Real ub;
6801 
6802  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6803  {
6804  if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6805  continue;
6806 
6807  /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6808  * variables, so this expression should either be an original variable or have an auxiliary variable
6809  */
6810  var = SCIPgetExprAuxVarNonlinear(expr);
6811  assert(var != NULL);
6812 
6813  lb = SCIPvarGetLbLocal(var);
6814  ub = SCIPvarGetUbLocal(var);
6815 
6816  /* skip already fixed variable */
6817  if( SCIPisEQ(scip, lb, ub) )
6818  {
6819  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6820  continue;
6821  }
6822 
6823  assert(*ncands + 1 < SCIPgetNVars(scip));
6824  cands[*ncands].expr = expr;
6825  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6826  ++(*ncands);
6827  }
6828  }
6829  }
6830 
6831  /* if we have branching candidates, then we don't need another attempt */
6832  if( *ncands > 0 )
6833  break;
6834  }
6835 
6836  if( it != NULL )
6837  SCIPfreeExpriter(&it);
6838 
6839  return SCIP_OKAY;
6840 }
6841 
6842 /** computes a branching score for a variable that reflects how important branching on this variable would be for
6843  * improving the dual bound from the LP relaxation
6844  *
6845  * Assume the Lagrangian for the current LP is something of the form
6846  * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6847  * where x are the original variables, z the auxiliary variables,
6848  * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6849  *
6850  * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6851  * If we could have used not only an estimator, but the actual function f(x), then this would
6852  * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6853  * Using a lot of handwaving, we claim that
6854  * lambda_i * (f(x) - a_i'x + b_i)
6855  * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6856  * If an estimator depended on local bounds, then it could be improved by branching.
6857  * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6858  *
6859  * 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.
6860  * To scale, we divide by the LP objective value (if >1).
6861  *
6862  * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6863  * these are affected by the bounds on original variables indirectly (through forward-propagation)
6864  *
6865  * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6866  * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6867  * would also be branching candidates
6868  */
6869 static
6871  SCIP* scip, /**< SCIP data structure */
6872  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6873  SCIP_VAR* var /**< variable */
6874  )
6875 {
6876  SCIP_COL* col;
6877  SCIP_ROW** rows;
6878  int nrows;
6879  int r;
6880  SCIP_Real dualscore;
6881 
6882  assert(scip != NULL);
6883  assert(conshdlr != NULL);
6884  assert(var != NULL);
6885 
6886  /* if LP not solved, then the dual branching score is not available */
6888  return 0.0;
6889 
6890  /* if var is not in the LP, then the dual branching score is not available */
6892  return 0.0;
6893 
6894  col = SCIPvarGetCol(var);
6895  assert(col != NULL);
6896 
6897  if( !SCIPcolIsInLP(col) )
6898  return 0.0;
6899 
6900  nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6901  rows = SCIPcolGetRows(col);
6902 
6903  /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6904 
6905  /* aggregate duals from all rows from consexpr with non-zero dual
6906  * TODO: this is a quick-and-dirty implementation, and not used by default
6907  * in the long run, this should be either removed or replaced by a proper implementation
6908  */
6909  dualscore = 0.0;
6910  for( r = 0; r < nrows; ++r )
6911  {
6912  SCIP_Real estimategap;
6913  const char* estimategapstr;
6914 
6915  /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6916  * these would typically be local, unless they are created at the root node
6917  * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6918  if( !SCIProwIsLocal(rows[r]) )
6919  continue;
6920  */
6921  if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6922  continue;
6923  if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6924  continue;
6925 
6926  estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6927  if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6928  continue;
6929  estimategap = atof(estimategapstr + 13);
6930  assert(estimategap >= 0.0);
6931  if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6932  estimategap = SCIPgetHugeValue(scip);
6933 
6934  /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6935  SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6936 
6937  dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6938  }
6939 
6940  /* divide by optimal value of LP for scaling */
6941  dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6942 
6943  return dualscore;
6944 }
6945 
6946 /** computes branching scores (including weighted score) for a set of candidates
6947  *
6948  * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6949  * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6950  *
6951  * For each score, compute the maximum over all candidates.
6952  *
6953  * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6954  * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6955  * score of all candidates.
6956  * Further divide by the sum of all weights where a score was available (even if the score was 0).
6957  *
6958  * For example:
6959  * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6960  * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6961  * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6962  * - 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.
6963  * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6964  */
6965 static
6967  SCIP* scip, /**< SCIP data structure */
6968  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6969  BRANCHCAND* cands, /**< branching candidates */
6970  int ncands, /**< number of candidates */
6971  SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6972  )
6973 {
6974  SCIP_CONSHDLRDATA* conshdlrdata;
6975  BRANCHCAND maxscore;
6976  int c;
6977 
6978  assert(scip != NULL);
6979  assert(conshdlr != NULL);
6980  assert(cands != NULL);
6981  assert(ncands > 0);
6982 
6983  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6984  assert(conshdlrdata != NULL);
6985 
6986  /* initialize counts to 0 */
6987  memset(&maxscore, 0, sizeof(BRANCHCAND));
6988 
6989  for( c = 0; c < ncands; ++c )
6990  {
6991  if( conshdlrdata->branchviolweight > 0.0 )
6992  {
6993  /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6994  maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6995  }
6996 
6997  if( conshdlrdata->branchdomainweight > 0.0 )
6998  {
6999  SCIP_Real domainwidth;
7000  SCIP_VAR* var;
7001 
7002  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7003  assert(var != NULL);
7004 
7005  /* get domain width, taking infinity at 1e20 on purpose */
7006  domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
7007 
7008  /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
7009  * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
7010  * the idea is to penalize very large and very small domains
7011  */
7012  if( domainwidth >= 1.0 )
7013  cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
7014  else
7015  cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
7016 
7017  maxscore.domain = MAX(cands[c].domain, maxscore.domain);
7018  }
7019  else
7020  cands[c].domain = 0.0;
7021 
7022  if( conshdlrdata->branchdualweight > 0.0 )
7023  {
7024  SCIP_VAR* var;
7025 
7026  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7027  assert(var != NULL);
7028 
7029  cands[c].dual = getDualBranchscore(scip, conshdlr, var);
7030  maxscore.dual = MAX(cands[c].dual, maxscore.dual);
7031  }
7032 
7033  if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
7034  {
7035  SCIP_VAR* var;
7036 
7037  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7038  assert(var != NULL);
7039 
7040  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
7041  cands[c].pscost = SCIP_INVALID;
7042  else
7043  {
7044  SCIP_Real brpoint;
7045  SCIP_Real pscostdown;
7046  SCIP_Real pscostup;
7047  char strategy;
7048 
7049  /* decide how to compute pseudo-cost scores
7050  * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
7051  * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
7052  */
7054  strategy = conshdlrdata->branchpscostupdatestrategy;
7055  else
7056  strategy = 'l';
7057 
7058  brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
7059 
7060  /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
7061  * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
7062  * For here, I use a simple #counts >= branchpscostreliable.
7063  * TODO use SCIPgetVarPseudocostCount() instead?
7064  */
7065  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7066  {
7067  switch( strategy )
7068  {
7069  case 's' :
7070  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
7071  break;
7072  case 'd' :
7073  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
7074  break;
7075  case 'l' :
7076  if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
7077  pscostdown = SCIP_INVALID;
7078  else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
7079  pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
7080  else
7081  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, NULL, var) - SCIPadjustedVarUb(scip, var, brpoint)));
7082  break;
7083  default :
7084  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7085  pscostdown = SCIP_INVALID;
7086  }
7087  }
7088  else
7089  pscostdown = SCIP_INVALID;
7090 
7091  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7092  {
7093  switch( strategy )
7094  {
7095  case 's' :
7096  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7097  break;
7098  case 'd' :
7099  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7100  break;
7101  case 'l' :
7102  if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7103  pscostup = SCIP_INVALID;
7104  else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7105  pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7106  else
7107  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, NULL, var) );
7108  break;
7109  default :
7110  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7111  pscostup = SCIP_INVALID;
7112  }
7113  }
7114  else
7115  pscostup = SCIP_INVALID;
7116 
7117  /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7118  * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7119  */
7120  if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7121  cands[c].pscost = SCIP_INVALID;
7122  else if( pscostdown == SCIP_INVALID )
7123  cands[c].pscost = pscostup;
7124  else if( pscostup == SCIP_INVALID )
7125  cands[c].pscost = pscostdown;
7126  else
7127  cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7128  }
7129 
7130  if( cands[c].pscost != SCIP_INVALID )
7131  maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7132  }
7133 
7134  if( conshdlrdata->branchvartypeweight > 0.0 )
7135  {
7136  SCIP_VAR* var;
7137 
7138  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7139  assert(var != NULL);
7140 
7141  switch( SCIPvarGetType(var) )
7142  {
7143  case SCIP_VARTYPE_BINARY :
7144  cands[c].vartype = 1.0;
7145  break;
7146  case SCIP_VARTYPE_INTEGER :
7147  cands[c].vartype = 0.1;
7148  break;
7149  case SCIP_VARTYPE_IMPLINT :
7150  cands[c].vartype = 0.01;
7151  break;
7153  default:
7154  cands[c].vartype = 0.0;
7155  }
7156  maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7157  }
7158  }
7159 
7160  /* now compute a weighted score for each candidate from the single scores
7161  * the single scores are scaled to be in [0,1] for this
7162  */
7163  for( c = 0; c < ncands; ++c )
7164  {
7165  SCIP_Real weightsum;
7166 
7167  ENFOLOG(
7168  SCIP_VAR* var;
7169  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
7170  SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7171  )
7172 
7173  cands[c].weighted = 0.0;
7174  weightsum = 0.0;
7175 
7176  if( maxscore.auxviol > 0.0 )
7177  {
7178  cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7179  weightsum += conshdlrdata->branchviolweight;
7180 
7181  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7182  }
7183 
7184  if( maxscore.domain > 0.0 )
7185  {
7186  cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7187  weightsum += conshdlrdata->branchdomainweight;
7188 
7189  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7190  }
7191 
7192  if( maxscore.dual > 0.0 )
7193  {
7194  cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7195  weightsum += conshdlrdata->branchdualweight;
7196 
7197  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7198  }
7199 
7200  if( maxscore.pscost > 0.0 )
7201  {
7202  /* use pseudo-costs only if available */
7203  if( cands[c].pscost != SCIP_INVALID )
7204  {
7205  cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7206  weightsum += conshdlrdata->branchpscostweight;
7207 
7208  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7209  }
7210  else
7211  {
7212  /* do not add pscostscore, if not available, also do not add into weightsum */
7213  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7214  }
7215  }
7216 
7217  if( maxscore.vartype > 0.0 )
7218  {
7219  cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7220  weightsum += conshdlrdata->branchvartypeweight;
7221 
7222  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7223  }
7224  assert(weightsum > 0.0); /* we should have got at least one valid score */
7225  cands[c].weighted /= weightsum;
7226 
7227  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7228  }
7229 }
7230 
7231 /** compare two branching candidates by their weighted score
7232  *
7233  * if weighted score is equal, use variable index of (aux)var
7234  */
7235 static
7236 SCIP_DECL_SORTINDCOMP(branchcandCompare)
7238  BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7239 
7240  if( cands[ind1].weighted != cands[ind2].weighted )
7241  return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7242  else
7243  return SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind1].expr)) - SCIPvarGetIndex(SCIPgetExprAuxVarNonlinear(cands[ind2].expr));
7244 }
7245 
7246 /** do branching or register branching candidates */
7247 static
7249  SCIP* scip, /**< SCIP data structure */
7250  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7251  SCIP_CONS** conss, /**< constraints to process */
7252  int nconss, /**< number of constraints */
7253  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7254  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7255  SCIP_Longint soltag, /**< tag of solution */
7256  SCIP_RESULT* result /**< pointer to store the result of branching */
7257  )
7258 {
7259  SCIP_CONSHDLRDATA* conshdlrdata;
7260  BRANCHCAND* cands;
7261  int ncands;
7262  SCIP_VAR* var;
7263  SCIP_NODE* downchild;
7264  SCIP_NODE* eqchild;
7265  SCIP_NODE* upchild;
7266 
7267  assert(conshdlr != NULL);
7268  assert(result != NULL);
7269 
7270  *result = SCIP_DIDNOTFIND;
7271 
7272  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7273  assert(conshdlrdata != NULL);
7274 
7275  if( conshdlrdata->branchexternal )
7276  {
7277  /* just register branching candidates as external */
7278  SCIP_Bool success;
7279 
7280  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7281  if( success )
7282  *result = SCIP_INFEASIBLE;
7283 
7284  return SCIP_OKAY;
7285  }
7286 
7287  /* collect branching candidates and their auxviol-score */
7288  SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip)) );
7289  SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7290 
7291  /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7292  * we will return here and let the fallbacks in consEnfo() decide how to proceed
7293  */
7294  if( ncands == 0 )
7295  goto TERMINATE;
7296 
7297  if( ncands > 1 )
7298  {
7299  /* if there are more than one candidate, then compute scores and select */
7300  int* perm;
7301  int c;
7302  int left;
7303  int right;
7304  SCIP_Real threshold;
7305 
7306  /* compute additional scores on branching candidates and weighted score */
7307  scoreBranchingCandidates(scip, conshdlr, cands, ncands, sol);
7308 
7309  /* sort candidates by weighted score */
7310  SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7311  SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7312 
7313  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7314  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7315  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7316 
7317  /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7318  left = 0;
7319  right = ncands - 1;
7320  threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7321  while( left < right )
7322  {
7323  int mid = (left + right) / 2;
7324  if( cands[perm[mid]].weighted >= threshold )
7325  left = mid + 1;
7326  else
7327  right = mid;
7328  }
7329  assert(left <= ncands);
7330 
7331  if( left < ncands )
7332  {
7333  if( cands[perm[left]].weighted >= threshold )
7334  {
7335  assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7336  ncands = left + 1;
7337  }
7338  else
7339  {
7340  assert(cands[perm[left]].weighted < threshold);
7341  ncands = left;
7342  }
7343  }
7344  assert(ncands > 0);
7345 
7346  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7347  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr)), cands[perm[0]].weighted,
7348  SCIPvarGetName(SCIPgetExprAuxVarNonlinear(cands[perm[ncands - 1]].expr)), cands[perm[ncands - 1]].weighted); )
7349 
7350  if( ncands > 1 )
7351  {
7352  /* choose at random from candidates 0..ncands-1 */
7353  if( conshdlrdata->branchrandnumgen == NULL )
7354  {
7355  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7356  }
7357  c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7358  var = SCIPgetExprAuxVarNonlinear(cands[perm[c]].expr);
7359  }
7360  else
7361  var = SCIPgetExprAuxVarNonlinear(cands[perm[0]].expr);
7362 
7363  SCIPfreeBufferArray(scip, &perm);
7364  }
7365  else
7366  {
7367  var = SCIPgetExprAuxVarNonlinear(cands[0].expr);
7368  }
7369  assert(var != NULL);
7370 
7371  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(var),
7372  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)); )
7373 
7374  SCIP_CALL( SCIPbranchVarVal(scip, var, SCIPgetBranchingPoint(scip, var, SCIP_INVALID), &downchild, &eqchild,
7375  &upchild) );
7376  if( downchild != NULL || eqchild != NULL || upchild != NULL )
7377  *result = SCIP_BRANCHED;
7378  else
7379  /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7380  *result = SCIP_REDUCEDDOM;
7381 
7382  TERMINATE:
7383  SCIPfreeBufferArray(scip, &cands);
7384 
7385  return SCIP_OKAY;
7386 }
7387 
7388 /** call enforcement or estimate callback of nonlinear handler
7389  *
7390  * Calls the enforcement callback, if available.
7391  * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7392  *
7393  * If cut is weak, but estimator is not tight, tries to add branching candidates.
7394  */
7395 static
7397  SCIP* scip, /**< SCIP main data structure */
7398  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7399  SCIP_CONS* cons, /**< nonlinear constraint */
7400  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7401  SCIP_EXPR* expr, /**< expression */
7402  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7403  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7404  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7405  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7406  SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7407  SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7408  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7409  SCIP_RESULT* result /**< pointer to store the result */
7410  )
7411 {
7412  assert(result != NULL);
7413 
7414  /* call enforcement callback of the nlhdlr */
7415  SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7416  allowweakcuts, separated, inenforcement, result) );
7417 
7418  /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7419  if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7420  {
7421  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr %s succeeded with result %d\n",
7422  SCIPnlhdlrGetName(nlhdlr), *result); )
7423  return SCIP_OKAY;
7424  }
7425  else
7426  {
7427  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " sepa of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7428  }
7429 
7430  *result = SCIP_DIDNOTFIND;
7431 
7432  /* now call the estimator callback of the nlhdlr */
7433  if( SCIPnlhdlrHasEstimate(nlhdlr) )
7434  {
7435  SCIP_VAR* auxvar;
7436  SCIP_Bool sepasuccess = FALSE;
7437  SCIP_Bool branchscoresuccess = FALSE;
7438  SCIP_PTRARRAY* rowpreps;
7439  int minidx;
7440  int maxidx;
7441  int r;
7442  SCIP_ROWPREP* rowprep;
7443 
7444  SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7445 
7446  auxvar = SCIPgetExprAuxVarNonlinear(expr);
7447  assert(auxvar != NULL);
7448 
7449  SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7450  SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7451 
7452  minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7453  maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7454 
7455  assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7456 
7457  if( !sepasuccess )
7458  {
7459  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7460  SCIPnlhdlrGetName(nlhdlr)); )
7461  }
7462 
7463  for( r = minidx; r <= maxidx; ++r )
7464  {
7465  rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7466 
7467  assert(rowprep != NULL);
7468  assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7469 
7470  /* complete estimator to cut */
7471  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7472 
7473  /* add the cut and/or branching scores */
7474  SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7475  auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7476 
7477  SCIPfreeRowprep(scip, &rowprep);
7478  }
7479 
7480  SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7481  }
7482 
7483  return SCIP_OKAY;
7484 }
7485 
7486 /** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7487  *
7488  * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7489  */
7490 static
7492  SCIP* scip, /**< SCIP data structure */
7493  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7494  SCIP_CONS* cons, /**< nonlinear constraint */
7495  SCIP_EXPR* expr, /**< expression */
7496  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7497  SCIP_Longint soltag, /**< tag of solution */
7498  SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7499  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7500  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7501  )
7502 {
7503  SCIP_CONSHDLRDATA* conshdlrdata;
7504  SCIP_EXPR_OWNERDATA* ownerdata;
7505  SCIP_Real origviol;
7506  SCIP_Bool underestimate;
7507  SCIP_Bool overestimate;
7508  SCIP_Real auxviol;
7509  SCIP_Bool auxunderestimate;
7510  SCIP_Bool auxoverestimate;
7511  SCIP_RESULT hdlrresult;
7512  int e;
7513 
7514  assert(scip != NULL);
7515  assert(expr != NULL);
7516  assert(result != NULL);
7517 
7518  ownerdata = SCIPexprGetOwnerData(expr);
7519  assert(ownerdata != NULL);
7520  assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7521 
7522  *result = SCIP_DIDNOTFIND;
7523 
7524  /* make sure that this expression has been evaluated */
7525  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7526 
7527  /* decide whether under- or overestimate is required and get amount of violation */
7528  origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7529 
7530  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7531  assert(conshdlrdata != NULL);
7532 
7533  /* no sufficient violation w.r.t. the original variables -> skip expression */
7534  if( !overestimate && !underestimate )
7535  {
7536  return SCIP_OKAY;
7537  }
7538 
7539  /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7540  for( e = 0; e < ownerdata->nenfos; ++e )
7541  {
7542  SCIP_NLHDLR* nlhdlr;
7543 
7544  /* skip nlhdlr that do not want to participate in any separation */
7545  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7546  continue;
7547 
7548  nlhdlr = ownerdata->enfos[e]->nlhdlr;
7549  assert(nlhdlr != NULL);
7550 
7551  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7552  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7553  ENFOLOG(
7554  SCIPinfoMessage(scip, enfologfile, " expr ");
7555  SCIPprintExpr(scip, expr, enfologfile);
7556  SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7557  "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7558  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7559  )
7560 
7561  /* TODO if expr is root of constraint (consdata->expr == expr),
7562  * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7563  * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7564  * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7565  * so we should enforce in these auxiliaries first
7566  * if changing this here, we must also adapt analyzeViolation()
7567  */
7568 
7569  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7570  assert(auxviol >= 0.0);
7571 
7572  /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7573  if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7574  {
7575  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7576  "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7577  SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7578 
7579  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7580  continue;
7581  }
7582 
7583  /* 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 */
7584  if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7585  {
7586  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7587  "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7588  underestimate, overestimate); )
7589 
7590  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7591  continue;
7592  }
7593 
7594  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7595  "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7596  auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7597 
7598  /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7599  * wants to be called for separation on this side, then call separation of nlhdlr
7600  */
7601  if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 )
7602  {
7603  /* call the separation or estimation callback of the nonlinear handler for overestimation */
7604  hdlrresult = SCIP_DIDNOTFIND;
7605  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7606  ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7607 
7608  if( hdlrresult == SCIP_CUTOFF )
7609  {
7610  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7611  *result = SCIP_CUTOFF;
7612  ownerdata->lastenforced = conshdlrdata->enforound;
7613  break;
7614  }
7615 
7616  if( hdlrresult == SCIP_SEPARATED )
7617  {
7618  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7619  *result = SCIP_SEPARATED;
7620  ownerdata->lastenforced = conshdlrdata->enforound;
7621  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7622  break;
7623  }
7624 
7625  if( hdlrresult == SCIP_REDUCEDDOM )
7626  {
7627  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7628  *result = SCIP_REDUCEDDOM;
7629  ownerdata->lastenforced = conshdlrdata->enforound;
7630  /* TODO or should we always just stop here? */
7631  }
7632 
7633  if( hdlrresult == SCIP_BRANCHED )
7634  {
7635  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7636  assert(inenforcement);
7637 
7638  /* separation and domain reduction takes precedence over branching */
7639  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7640  if( *result == SCIP_DIDNOTFIND )
7641  *result = SCIP_BRANCHED;
7642  ownerdata->lastenforced = conshdlrdata->enforound;
7643  }
7644  }
7645 
7646  /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7647  * wants to be called for separation on this side, then call separation of nlhdlr
7648  */
7649  if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 )
7650  {
7651  /* call the separation or estimation callback of the nonlinear handler for underestimation */
7652  hdlrresult = SCIP_DIDNOTFIND;
7653  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7654  ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, &hdlrresult) );
7655 
7656  if( hdlrresult == SCIP_CUTOFF )
7657  {
7658  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7659  *result = SCIP_CUTOFF;
7660  ownerdata->lastenforced = conshdlrdata->enforound;
7661  break;
7662  }
7663 
7664  if( hdlrresult == SCIP_SEPARATED )
7665  {
7666  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7667  *result = SCIP_SEPARATED;
7668  ownerdata->lastenforced = conshdlrdata->enforound;
7669  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7670  break;
7671  }
7672 
7673  if( hdlrresult == SCIP_REDUCEDDOM )
7674  {
7675  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7676  *result = SCIP_REDUCEDDOM;
7677  ownerdata->lastenforced = conshdlrdata->enforound;
7678  /* TODO or should we always just stop here? */
7679  }
7680 
7681  if( hdlrresult == SCIP_BRANCHED )
7682  {
7683  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7684  assert(inenforcement);
7685 
7686  /* separation takes precedence over branching */
7687  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7688  if( *result == SCIP_DIDNOTFIND )
7689  *result = SCIP_BRANCHED;
7690  ownerdata->lastenforced = conshdlrdata->enforound;
7691  }
7692  }
7693  }
7694 
7695  return SCIP_OKAY;
7696 }
7697 
7698 /** helper function to enforce a single constraint */
7699 static
7701  SCIP* scip, /**< SCIP data structure */
7702  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7703  SCIP_CONS* cons, /**< constraint to process */
7704  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7705  SCIP_Longint soltag, /**< tag of solution */
7706  SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7707  SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7708  SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7709  SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7710  SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7711  )
7712 {
7713  SCIP_CONSDATA* consdata;
7714  SCIP_CONSHDLRDATA* conshdlrdata;
7715  SCIP_EXPR* expr;
7716 
7717  assert(conshdlr != NULL);
7718  assert(cons != NULL);
7719  assert(it != NULL);
7720  assert(result != NULL);
7721  assert(success != NULL);
7722 
7723  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7724  assert(conshdlrdata != NULL);
7725 
7726  consdata = SCIPconsGetData(cons);
7727  assert(consdata != NULL);
7728  assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7729 
7730  *success = FALSE;
7731 
7732  if( inenforcement && !consdata->ispropagated )
7733  {
7734  /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7735  * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7736  * (TODO: nlhdlr tells us now whether they do and so we could skip).
7737  * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7738  * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7739  * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7740  * confuse the stalling check for how long to do separation).
7741  */
7742  SCIP_Bool infeasible;
7743  int ntightenings;
7744 
7745  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7746  if( infeasible )
7747  {
7748  *result = SCIP_CUTOFF;
7749  return SCIP_OKAY;
7750  }
7751  /* if we tightened an auxvar bound, we better communicate that */
7752  if( ntightenings > 0 )
7753  *result = SCIP_REDUCEDDOM;
7754  }
7755 
7756  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7757  {
7758  SCIP_EXPR_OWNERDATA* ownerdata;
7759  SCIP_RESULT resultexpr;
7760 
7761  ownerdata = SCIPexprGetOwnerData(expr);
7762  assert(ownerdata != NULL);
7763 
7764  /* we can only enforce if there is an auxvar to compare with */
7765  if( ownerdata->auxvar == NULL )
7766  continue;
7767 
7768  assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7769  if( ownerdata->lastenforced == conshdlrdata->enforound )
7770  {
7771  ENFOLOG(
7772  SCIPinfoMessage(scip, enfologfile, " skip expr ");
7773  SCIPprintExpr(scip, expr, enfologfile);
7774  SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7775  )
7776  *success = TRUE;
7777  continue;
7778  }
7779 
7780  SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, &resultexpr) );
7781 
7782  /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7783  assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7784  if( ownerdata->lastenforced == conshdlrdata->enforound )
7785  *success = TRUE;
7786 
7787  if( resultexpr == SCIP_CUTOFF )
7788  {
7789  *result = SCIP_CUTOFF;
7790  break;
7791  }
7792 
7793  if( resultexpr == SCIP_SEPARATED )
7794  *result = SCIP_SEPARATED;
7795 
7796  if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7797  *result = SCIP_REDUCEDDOM;
7798 
7799  if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7800  *result = SCIP_BRANCHED;
7801  }
7802 
7803  return SCIP_OKAY;
7804 }
7805 
7806 /** try to separate violated constraints and, if in enforcement, register branching scores
7807  *
7808  * Sets result to
7809  * - SCIP_DIDNOTFIND, if nothing of the below has been done
7810  * - SCIP_CUTOFF, if node can be cutoff,
7811  * - SCIP_SEPARATED, if a cut has been added,
7812  * - SCIP_REDUCEDDOM, if a domain reduction has been found,
7813  * - SCIP_BRANCHED, if branching has been done,
7814  * - SCIP_REDUCEDDOM, if a variable got fixed (in an attempt to branch on it),
7815  * - SCIP_INFEASIBLE, if external branching candidates were registered
7816  */
7817 static
7819  SCIP* scip, /**< SCIP data structure */
7820  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7821  SCIP_CONS** conss, /**< constraints to process */
7822  int nconss, /**< number of constraints */
7823  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7824  SCIP_Longint soltag, /**< tag of solution */
7825  SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7826  SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7827  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7828  )
7829 {
7830  SCIP_CONSHDLRDATA* conshdlrdata;
7831  SCIP_EXPRITER* it;
7832  SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7833  int c;
7834 
7835  assert(conshdlr != NULL);
7836  assert(conss != NULL || nconss == 0);
7837  assert(result != NULL);
7838 
7839  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7840  assert(conshdlrdata != NULL);
7841 
7842  /* increase tag to tell whether branching scores in expression belong to this sweep
7843  * and which expressions have already been enforced in this sweep
7844  * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7845  */
7846  ++(conshdlrdata->enforound);
7847 
7848  *result = SCIP_DIDNOTFIND;
7849 
7850  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7852 
7853  for( c = 0; c < nconss; ++c )
7854  {
7855  assert(conss != NULL && conss[c] != NULL);
7856 
7857  /* skip constraints that are not enabled or deleted */
7858  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7859  continue;
7860  assert(SCIPconsIsActive(conss[c]));
7861 
7862  /* skip constraints that have separation disabled if we are only in separation */
7863  if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7864  continue;
7865 
7866  /* skip non-violated constraints */
7867  if( !isConsViolated(scip, conss[c]) )
7868  continue;
7869 
7870  ENFOLOG(
7871  {
7872  SCIP_CONSDATA* consdata;
7873  int i;
7874  consdata = SCIPconsGetData(conss[c]);
7875  assert(consdata != NULL);
7876  SCIPinfoMessage(scip, enfologfile, " constraint ");
7877  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7878  SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7879  for( i = 0; i < consdata->nvarexprs; ++i )
7880  {
7881  SCIP_VAR* var;
7882  var = SCIPgetVarExprVar(consdata->varexprs[i]);
7883  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7884  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7885  }
7886  })
7887 
7888  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, result, &consenforced) );
7889 
7890  if( *result == SCIP_CUTOFF )
7891  break;
7892 
7893  if( !consenforced && inenforcement )
7894  {
7895  SCIP_Real viol;
7896 
7897  SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7898  if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7899  {
7900  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7901  "cuts allowed\n", SCIPconsGetName(conss[c])); )
7902 
7903  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, result, &consenforced) );
7904 
7905  if( consenforced )
7906  ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7907 
7908  if( *result == SCIP_CUTOFF )
7909  break;
7910  }
7911  }
7912  }
7913 
7914  SCIPfreeExpriter(&it);
7915 
7916  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7917 
7918  /* if having branching scores, then propagate them from expressions with children to variable expressions */
7919  if( *result == SCIP_BRANCHED )
7920  {
7921  /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7922  * branching
7923  */
7924  SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7925 
7926  /* branching should either have branched: result == SCIP_BRANCHED,
7927  * or fixed a variable: result == SCIP_REDUCEDDOM,
7928  * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7929  * or have not done anything: result == SCIP_DIDNOTFIND
7930  */
7931  assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7932  }
7933 
7934  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7935 
7936  return SCIP_OKAY;
7937 }
7938 
7939 /** collect (and print (if debugging enfo)) information on violation in expressions
7940  *
7941  * assumes that constraint violations have been computed
7942  */
7943 static
7945  SCIP* scip, /**< SCIP data structure */
7946  SCIP_CONS** conss, /**< constraints */
7947  int nconss, /**< number of constraints */
7948  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7949  SCIP_Longint soltag, /**< tag of solution */
7950  SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
7951  SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
7952  SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
7953  SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
7954  SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
7955  )
7956 {
7957  SCIP_CONSDATA* consdata;
7958  SCIP_EXPRITER* it;
7959  SCIP_EXPR* expr;
7960  SCIP_Real v;
7961  int c;
7962 
7963  assert(conss != NULL || nconss == 0);
7964  assert(maxabsconsviol != NULL);
7965  assert(maxrelconsviol != NULL);
7966  assert(maxauxviol != NULL);
7967  assert(maxvarboundviol != NULL);
7968 
7969  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7971 
7972  *maxabsconsviol = 0.0;
7973  *maxrelconsviol = 0.0;
7974  *minauxviol = SCIPinfinity(scip);
7975  *maxauxviol = 0.0;
7976  *maxvarboundviol = 0.0;
7977 
7978  for( c = 0; c < nconss; ++c )
7979  {
7980  assert(conss != NULL && conss[c] != NULL);
7981 
7982  consdata = SCIPconsGetData(conss[c]);
7983  assert(consdata != NULL);
7984 
7985  /* skip constraints that are not enabled, deleted, or have separation disabled */
7986  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
7987  continue;
7988  assert(SCIPconsIsActive(conss[c]));
7989 
7990  v = getConsAbsViolation(conss[c]);
7991  *maxabsconsviol = MAX(*maxabsconsviol, v);
7992 
7993  /* skip non-violated constraints */
7994  if( !isConsViolated(scip, conss[c]) )
7995  continue;
7996 
7997  SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
7998  *maxrelconsviol = MAX(*maxrelconsviol, v);
7999 
8000  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8001  {
8002  SCIP_EXPR_OWNERDATA* ownerdata;
8003  SCIP_Real auxvarvalue;
8004  SCIP_Real auxvarlb;
8005  SCIP_Real auxvarub;
8006  SCIP_Bool violunder;
8007  SCIP_Bool violover;
8008  SCIP_Real origviol;
8009  SCIP_Real auxviol;
8010  int e;
8011 
8012  ownerdata = SCIPexprGetOwnerData(expr);
8013  assert(ownerdata != NULL);
8014 
8015  if( ownerdata->auxvar == NULL )
8016  {
8017  /* check violation of variable bounds of original variable */
8018  if( SCIPisExprVar(scip, expr) )
8019  {
8020  SCIP_VAR* var;
8021  var = SCIPgetVarExprVar(expr);
8022  auxvarvalue = SCIPgetSolVal(scip, sol, var);
8023  auxvarlb = SCIPvarGetLbLocal(var);
8024  auxvarub = SCIPvarGetUbLocal(var);
8025 
8026  origviol = 0.0;
8027  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8028  origviol = auxvarlb - auxvarvalue;
8029  else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8030  origviol = auxvarvalue - auxvarub;
8031  if( origviol <= 0.0 )
8032  continue;
8033 
8034  *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8035 
8036  ENFOLOG(
8037  SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8038  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8039  SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8040  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8041  SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8042  SCIPinfoMessage(scip, enfologfile, "\n");
8043  )
8044  }
8045 
8046  continue;
8047  }
8048 
8049  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8050  auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8051  auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8052 
8053  /* check violation of variable bounds of auxiliary variable */
8054  if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8055  *maxvarboundviol = auxvarlb - auxvarvalue;
8056  else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8057  *maxvarboundviol = auxvarvalue - auxvarub;
8058 
8059  origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8060 
8061  ENFOLOG(
8062  if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8063  {
8064  SCIPinfoMessage(scip, enfologfile, "expr ");
8065  SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8066  SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8067 
8068  SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8069  if( origviol > 0.0 )
8070  SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8071  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8072  SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8073  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8074  SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8075  SCIPinfoMessage(scip, enfologfile, "\n");
8076  }
8077  )
8078 
8079  /* no violation w.r.t. the original variables -> skip expression */
8080  if( origviol == 0.0 )
8081  continue;
8082 
8083  /* compute aux-violation for each nonlinear handlers */
8084  for( e = 0; e < ownerdata->nenfos; ++e )
8085  {
8086  SCIP_NLHDLR* nlhdlr;
8087 
8088  /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8089  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8090  continue;
8091 
8092  nlhdlr = ownerdata->enfos[e]->nlhdlr;
8093  assert(nlhdlr != NULL);
8094 
8095  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8096  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8097 
8098  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8099 
8100  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8101 
8102  if( auxviol > 0.0 )
8103  {
8104  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8105  *maxauxviol = MAX(*maxauxviol, auxviol);
8106  *minauxviol = MIN(*minauxviol, auxviol);
8107  }
8108  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8109  }
8110  }
8111  }
8112 
8113  SCIPfreeExpriter(&it);
8114 
8115  return SCIP_OKAY;
8116 } /*lint !e715*/
8117 
8118 /** enforcement of constraints called by enfolp and enforelax */
8119 static
8121  SCIP* scip, /**< SCIP data structure */
8122  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8123  SCIP_CONS** conss, /**< constraints to process */
8124  int nconss, /**< number of constraints */
8125  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8126  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8127  )
8128 {
8129  SCIP_CONSHDLRDATA* conshdlrdata;
8130  SCIP_Real maxabsconsviol;
8131  SCIP_Real maxrelconsviol;
8132  SCIP_Real minauxviol;
8133  SCIP_Real maxauxviol;
8134  SCIP_Real maxvarboundviol;
8135  SCIP_Longint soltag;
8136  int nnotify;
8137  int c;
8138 
8139  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8140  assert(conshdlr != NULL);
8141 
8142  soltag = SCIPgetExprNewSoltag(scip);
8143 
8144  *result = SCIP_FEASIBLE;
8145  for( c = 0; c < nconss; ++c )
8146  {
8147  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8148 
8149  if( isConsViolated(scip, conss[c]) )
8150  *result = SCIP_INFEASIBLE;
8151  }
8152 
8153  if( *result == SCIP_FEASIBLE )
8154  {
8155  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8157  return SCIP_OKAY;
8158  }
8159 
8160  SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8161  &minauxviol, &maxauxviol, &maxvarboundviol) );
8162 
8163  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8164  "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8165  SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8166  maxvarboundviol, SCIPgetLPFeastol(scip)); )
8167 
8168  assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8169 
8170  /* try to propagate */
8171  if( conshdlrdata->propinenforce )
8172  {
8173  SCIP_RESULT propresult;
8174  int nchgbds = 0;
8175 
8176  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8177 
8178  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8179  {
8180  *result = propresult;
8181  return SCIP_OKAY;
8182  }
8183  }
8184 
8185  /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8186  * all violated expr/auxvar in violated constraints)
8187  */
8188  if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8189  sol == NULL )
8190  {
8191  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8192  ++conshdlrdata->ntightenlp;
8193 
8194  *result = SCIP_SOLVELP;
8195 
8196  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8197  "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8198 
8199  return SCIP_OKAY;
8200  }
8201 
8202  /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8203  * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8204  */
8205  if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8206  {
8207  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8208  ++conshdlrdata->ntightenlp;
8209 
8210  *result = SCIP_SOLVELP;
8211 
8212  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8213 
8214  return SCIP_OKAY;
8215  }
8216 
8217  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, maxrelconsviol, result) );
8218 
8219  if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8220  *result == SCIP_INFEASIBLE )
8221  return SCIP_OKAY;
8222 
8223  assert(*result == SCIP_DIDNOTFIND);
8224 
8225  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8226  "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8227 
8228  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8229  {
8230  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8231  ++conshdlrdata->ntightenlp;
8232 
8233  *result = SCIP_SOLVELP;
8234 
8235  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8236  "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8237 
8238  return SCIP_OKAY;
8239  }
8240 
8241  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8242  SCIPgetLPFeastol(scip)) && sol == NULL )
8243  {
8244  /* try whether tighten the LP feasibility tolerance could help
8245  * maybe it is just some cut that hasn't been taken into account sufficiently
8246  * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8247  * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8248  * until the LP feastol reaches epsilon
8249  * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8250  * when maxauxviol is above LP feastol)
8251  */
8252  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8253  ++conshdlrdata->ndesperatetightenlp;
8254 
8255  *result = SCIP_SOLVELP;
8256 
8257  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8258 
8259  return SCIP_OKAY;
8260  }
8261 
8262  /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8263  if( !conshdlrdata->propinenforce )
8264  {
8265  SCIP_RESULT propresult;
8266  int nchgbds = 0;
8267 
8268  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8269 
8270  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8271  {
8272  *result = propresult;
8273  return SCIP_OKAY;
8274  }
8275  }
8276 
8277  /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8278  * now look if we find any unfixed variable that we could still branch on
8279  */
8280  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8281 
8282  if( nnotify > 0 )
8283  {
8284  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8285  ++conshdlrdata->ndesperatebranch;
8286 
8287  *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8288 
8289  return SCIP_OKAY;
8290  }
8291 
8292  /* if everything is fixed in violated constraints, then let's cut off the node
8293  * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8294  * result may not be conclusive (when constraint violations are small)
8295  * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8296  * sufficiently (see st_e40)
8297  * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8298  * not "desperate", but a pretty obvious thing to do
8299  */
8300  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8301  *result = SCIP_CUTOFF;
8302 
8303  /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8304  if( !SCIPisZero(scip, maxvarboundviol) )
8305  ++conshdlrdata->ndesperatecutoff;
8306 
8307  return SCIP_OKAY;
8308 }
8309 
8310 /** separation for all violated constraints to be used by SEPA callbacks */
8311 static
8313  SCIP* scip, /**< SCIP data structure */
8314  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8315  SCIP_CONS** conss, /**< constraints to process */
8316  int nconss, /**< number of constraints */
8317  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8318  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8319  )
8320 {
8321  SCIP_Longint soltag;
8322  SCIP_Bool haveviol = FALSE;
8323  int c;
8324 
8325  *result = SCIP_DIDNOTFIND;
8326 
8327  soltag = SCIPgetExprNewSoltag(scip);
8328 
8329  /* compute violations */
8330  for( c = 0; c < nconss; ++c )
8331  {
8332  assert(conss[c] != NULL);
8333 
8334  /* skip constraints that are not enabled, deleted, or have separation disabled */
8335  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8336  continue;
8337  assert(SCIPconsIsActive(conss[c]));
8338 
8339  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8340 
8341  if( isConsViolated(scip, conss[c]) )
8342  haveviol = TRUE;
8343  }
8344 
8345  /* if none of our constraints are violated, don't attempt separation */
8346  if( !haveviol )
8347  {
8348  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8349  return SCIP_OKAY;
8350  }
8351 
8352  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8353 
8354  /* call separation */
8355  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, SCIP_INVALID, result) );
8356 
8357  return SCIP_OKAY;
8358 }
8359 
8360 /** hash key retrieval function for bilinear term entries */
8361 static
8362 SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8363 { /*lint --e{715}*/
8364  SCIP_CONSHDLRDATA* conshdlrdata;
8365  int idx;
8366 
8367  conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8368  assert(conshdlrdata != NULL);
8369 
8370  idx = ((int)(size_t)elem) - 1;
8371  assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8372 
8373  return (void*)&conshdlrdata->bilinterms[idx];
8374 }
8375 
8376 /** returns TRUE iff the bilinear term entries are equal */
8377 static
8378 SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8379 { /*lint --e{715}*/
8382 
8383  /* get corresponding entries */
8384  entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8385  entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8386  assert(entry1->x != NULL && entry1->y != NULL);
8387  assert(entry2->x != NULL && entry2->y != NULL);
8388  assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8389  assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8390 
8391  return entry1->x == entry2->x && entry1->y == entry2->y;
8392 }
8393 
8394 /** returns the hash value of the key */
8395 static
8396 SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8397 { /*lint --e{715}*/
8399 
8400  entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8401  assert(entry->x != NULL && entry->y != NULL);
8402  assert(SCIPvarCompare(entry->x, entry->y) < 1);
8403 
8404  return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8405 }
8406 
8407 /** compare two auxiliary expressions
8408  *
8409  * Compares auxiliary variables, followed by coefficients, and then constants.
8410  */
8411 static
8412 SCIP_DECL_SORTPTRCOMP(auxexprComp)
8416  int compvars;
8417  int i;
8418 
8419  /* compare the auxiliary variables */
8420  compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8421 
8422  if( compvars != 0 )
8423  return compvars;
8424 
8425  /* compare the coefficients and constants */
8426  for( i = 0; i < 3; ++i )
8427  {
8428  if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8429  return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8430  }
8431 
8432  return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8433 }
8434 
8435 /* add an auxiliary expression to a bilinear term */
8436 static
8438  SCIP* scip, /**< SCIP data structure */
8439  SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8440  SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8441  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8442  SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8443  )
8444 {
8445  SCIP_Bool found;
8446  int pos;
8447  int i;
8448 
8449  *added = FALSE;
8450 
8451  /* check if auxexpr has already been added to term */
8452  if( term->nauxexprs == 0 )
8453  {
8454  found = FALSE;
8455  pos = 0;
8456  }
8457  else
8458  {
8459  found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8460  }
8461 
8462  if( !found )
8463  {
8464  if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8465  return SCIP_OKAY;
8466 
8467  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8468  assert(term->auxexprssize >= term->nauxexprs + 1);
8469 
8470  /* insert expression at the correct position */
8471  for( i = term->nauxexprs; i > pos; --i )
8472  {
8473  term->aux.exprs[i] = term->aux.exprs[i-1];
8474  }
8475  term->aux.exprs[pos] = auxexpr;
8476  ++(term->nauxexprs);
8477  *added = TRUE;
8478  }
8479  else
8480  {
8481  term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8482  term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8483  }
8484 
8485  return SCIP_OKAY;
8486 }
8487 
8488 /** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8489 static
8491  SCIP* scip, /**< SCIP data structure */
8492  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8493  SCIP_CONS** conss, /**< nonlinear constraints */
8494  int nconss /**< total number of nonlinear constraints */
8495  )
8496 {
8497  SCIP_CONSHDLRDATA* conshdlrdata;
8498  SCIP_EXPRITER* it;
8499  int c;
8500 
8501  assert(conss != NULL || nconss == 0);
8502 
8503  if( nconss == 0 )
8504  return SCIP_OKAY;
8505 
8506  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8507  assert(conshdlrdata != NULL);
8508 
8509  /* check whether the bilinear terms have been stored already */
8510  if( conshdlrdata->bilinterms != NULL )
8511  return SCIP_OKAY;
8512 
8513  /* create and initialize iterator */
8514  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8517 
8518  /* iterate through all constraints */
8519  for( c = 0; c < nconss; ++c )
8520  {
8521  SCIP_CONSDATA* consdata;
8522  SCIP_EXPR* expr;
8523 
8524  assert(conss != NULL && conss[c] != NULL);
8525  consdata = SCIPconsGetData(conss[c]);
8526  assert(consdata != NULL);
8527 
8528  /* iterate through all expressions */
8529  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8530  {
8531  SCIP_EXPR** children = SCIPexprGetChildren(expr);
8532  SCIP_VAR* x = NULL;
8533  SCIP_VAR* y = NULL;
8534 
8535  /* check whether the expression is of the form f(..)^2 */
8536  if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8537  {
8538  x = SCIPgetExprAuxVarNonlinear(children[0]);
8539  y = x;
8540  }
8541  /* check whether the expression is of the form f(..) * g(..) */
8542  else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8543  {
8544  x = SCIPgetExprAuxVarNonlinear(children[0]);
8545  y = SCIPgetExprAuxVarNonlinear(children[1]);
8546  }
8547 
8548  /* add variables to the hash table */
8549  if( x != NULL && y != NULL )
8550  {
8553  }
8554  }
8555  }
8556 
8557  /* release iterator */
8558  SCIPfreeExpriter(&it);
8559 
8560  return SCIP_OKAY;
8561 }
8562 
8563 /** store x, y and the locks in a new bilinear term */
8564 static
8566  SCIP* scip, /**< SCIP data structure */
8567  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8568  SCIP_VAR* x, /**< the first variable */
8569  SCIP_VAR* y, /**< the second variable */
8570  int nlockspos, /**< number of positive locks of the bilinear term */
8571  int nlocksneg, /**< number of negative locks of the bilinear term */
8572  int* idx, /**< pointer to store the position of the term in bilinterms array */
8573  SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8574  )
8575 {
8576  SCIP_CONSHDLRDATA* conshdlrdata;
8578 
8579  assert(conshdlr != NULL);
8580  assert(x != NULL);
8581  assert(y != NULL);
8582  assert(nlockspos >= 0);
8583  assert(nlocksneg >= 0);
8584 
8585  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8586  assert(conshdlrdata != NULL);
8587 
8588  /* ensure that x.index <= y.index */
8589  if( SCIPvarCompare(x, y) == 1 )
8590  {
8591  SCIPswapPointers((void**)&x, (void**)&y);
8592  }
8593  assert(SCIPvarCompare(x, y) < 1);
8594 
8595  *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8596 
8597  /* update or create the term */
8598  if( *idx >= 0 )
8599  { /* the term has already been added */
8600  assert(conshdlrdata->bilinterms[*idx].x == x);
8601  assert(conshdlrdata->bilinterms[*idx].y == y);
8602 
8603  /* get term and add locks */
8604  term = &conshdlrdata->bilinterms[*idx];
8605  assert(existing <= term->existing); /* implicit terms are added after existing ones */
8606  term->nlockspos += nlockspos;
8607  term->nlocksneg += nlocksneg;
8608  }
8609  else
8610  { /* this is the first time we encounter this product */
8611  /* ensure size of bilinterms array */
8612  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8613 
8614  *idx = conshdlrdata->nbilinterms;
8615 
8616  /* get term and set values in the created bilinear term */
8617  term = &conshdlrdata->bilinterms[*idx];
8618  assert(term != NULL);
8619  term->x = x;
8620  term->y = y;
8621  term->nauxexprs = 0;
8622  term->auxexprssize = 0;
8623  term->nlockspos = nlockspos;
8624  term->nlocksneg = nlocksneg;
8625  term->existing = existing;
8626  if( existing )
8627  term->aux.var = NULL;
8628  else
8629  term->aux.exprs = NULL;
8630 
8631  /* increase the total number of bilinear terms */
8632  ++(conshdlrdata->nbilinterms);
8633 
8634  /* save to the hashtable */
8635  if( conshdlrdata->bilinhashtable == NULL )
8636  {
8637  SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8638  bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8639  (void*)conshdlrdata) );
8640  }
8641  assert(conshdlrdata->bilinhashtable != NULL);
8642 
8643  /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8644  * because zero can not be inserted into hash table
8645  */
8646  SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8647 
8648  /* capture product variables */
8649  SCIP_CALL( SCIPcaptureVar(scip, x) );
8650  SCIP_CALL( SCIPcaptureVar(scip, y) );
8651  }
8652 
8653  return SCIP_OKAY;
8654 }
8655 
8656 /** frees array of bilinear terms and hash table */
8657 static
8659  SCIP* scip, /**< SCIP data structure */
8660  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8661  )
8662 {
8663  int i;
8664  int j;
8665 
8666  assert(conshdlrdata != NULL);
8667 
8668  /* check whether bilinear terms have been stored */
8669  if( conshdlrdata->bilinterms == NULL )
8670  {
8671  assert(conshdlrdata->bilinterms == NULL);
8672  assert(conshdlrdata->nbilinterms == 0);
8673  assert(conshdlrdata->bilintermssize == 0);
8674 
8675  return SCIP_OKAY;
8676  }
8677 
8678  /* release variables */
8679  for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8680  {
8681  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8682  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8683 
8684  for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8685  {
8686  if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8687  {
8688  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8689  }
8690  SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8691  }
8692 
8693  if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8694  {
8695  SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8696  continue;
8697  }
8698 
8699  /* the rest is for simple terms with a single auxvar */
8700 
8701  /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8702  if( conshdlrdata->bilinterms[i].aux.var != NULL )
8703  {
8704  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8705  }
8706  }
8707 
8708  /* free hash table */
8709  if( conshdlrdata->bilinhashtable != NULL )
8710  {
8711  SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8712  }
8713 
8714  /* free bilinterms array; reset counters */
8715  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8716  conshdlrdata->nbilinterms = 0;
8717  conshdlrdata->bilintermssize = 0;
8718 
8719  return SCIP_OKAY;
8720 }
8721 
8722 /*
8723  * vertex polyhedral separation
8724  */
8725 
8726 /** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8727 static
8729  SCIP* scip, /**< SCIP data structure */
8730  int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
8731  SCIP_LPI** lp /**< pointer to store created LP */
8732  )
8733 {
8734  SCIP_Real* obj;
8735  SCIP_Real* lb;
8736  SCIP_Real* ub;
8737  SCIP_Real* val;
8738  int* beg;
8739  int* ind;
8740  unsigned int nnonz;
8741  unsigned int ncols;
8742  unsigned int nrows;
8743  unsigned int i;
8744  unsigned int k;
8745 
8746  assert(scip != NULL);
8747  assert(lp != NULL);
8748  assert(nvars > 0);
8749  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8750 
8751  SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8752 
8753  /* create lpi to store the LP */
8754  SCIP_CALL( SCIPlpiCreate(lp, SCIPgetMessagehdlr(scip), "facet finding LP", SCIP_OBJSEN_MINIMIZE) );
8755 
8756  nrows = (unsigned int)nvars + 1;
8757  ncols = POWEROFTWO((unsigned int)nvars);
8758  nnonz = (ncols * (nrows + 1)) / 2;
8759 
8760  /* allocate necessary memory; set obj, lb, and ub to zero */
8761  SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
8762  SCIP_CALL( SCIPallocClearBufferArray(scip, &lb, ncols) );
8763  SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8764  SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8765  SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8766  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8767 
8768  /* calculate nonzero entries in the LP */
8769  for( i = 0, k = 0; i < ncols; ++i )
8770  {
8771  int row;
8772  unsigned int a;
8773 
8774  /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8775  ub[i] = SCIPlpiInfinity(*lp);
8776 
8777  SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8778  beg[i] = (int)k;
8779  row = 0;
8780 
8781  /* iterate through the bit representation of i */
8782  a = 1;
8783  while( a <= i )
8784  {
8785  if( (a & i) != 0 )
8786  {
8787  val[k] = 1.0;
8788  ind[k] = row;
8789 
8790  SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
8791 
8792  ++k;
8793  }
8794 
8795  a <<= 1;
8796  ++row;
8797  assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8798  assert(POWEROFTWO(row) == a);
8799  }
8800 
8801  /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8802  val[k] = 1.0;
8803  ind[k] = (int)nrows - 1;
8804  ++k;
8805  SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
8806  }
8807  assert(k == nnonz);
8808 
8809  /* load all data into LP interface
8810  * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
8811  */
8812  assert(nrows <= ncols);
8814  (int)ncols, obj, lb, ub, NULL,
8815  (int)nrows, lb, lb, NULL,
8816  (int)nnonz, beg, ind, val) );
8817 
8818  /* for the last row, we can set the rhs to 1.0 already */
8819  ind[0] = (int)nrows - 1;
8820  val[0] = 1.0;
8821  SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
8822 
8823  /* free allocated memory */
8824  SCIPfreeBufferArray(scip, &ind);
8825  SCIPfreeBufferArray(scip, &val);
8826  SCIPfreeBufferArray(scip, &beg);
8827  SCIPfreeBufferArray(scip, &ub);
8828  SCIPfreeBufferArray(scip, &lb);
8829  SCIPfreeBufferArray(scip, &obj);
8830 
8831  return SCIP_OKAY;
8832 }
8833 
8834 /** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
8835  * \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
8836  * set of vertices of the domain
8837  */
8838 static
8840  SCIP* scip, /**< SCIP data structure */
8841  SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
8842  SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
8843  SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
8844  int nallvars, /**< number of all variables */
8845  int nvars, /**< number of unfixed variables */
8846  int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
8847  SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
8848  SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
8849  )
8850 {
8851  SCIP_Real maxerror;
8852  SCIP_Real facetval;
8853  SCIP_Real funval;
8854  SCIP_Real error;
8855  unsigned int i;
8856  unsigned int ncorners;
8857  unsigned int prev;
8858 
8859  assert(scip != NULL);
8860  assert(funvals != NULL);
8861  assert(box != NULL);
8862  assert(nonfixedpos != NULL);
8863  assert(facetcoefs != NULL);
8864 
8865  ncorners = POWEROFTWO(nvars);
8866  maxerror = 0.0;
8867 
8868  /* check the origin (all variables at lower bound) */
8869  facetval = facetconstant;
8870  for( i = 0; i < (unsigned int) nallvars; ++i )
8871  facetval += facetcoefs[i] * box[2*i];
8872 
8873  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8874  funval = funvals[0];
8875  if( overestimate )
8876  error = funval - facetval;
8877  else
8878  error = facetval - funval;
8879 
8880  /* update maximum error */
8881  maxerror = MAX(error, maxerror);
8882 
8883  prev = 0;
8884  for( i = 1; i < ncorners; ++i )
8885  {
8886  unsigned int gray;
8887  unsigned int diff;
8888  unsigned int pos;
8889  int origpos;
8890 
8891  gray = i ^ (i >> 1);
8892  diff = gray ^ prev;
8893 
8894  /* compute position of unique 1 of diff */
8895  pos = 0;
8896  while( (diff >>= 1) != 0 )
8897  ++pos;
8898  assert(pos < (unsigned int)nvars);
8899 
8900  origpos = nonfixedpos[pos];
8901 
8902  if( gray > prev )
8903  facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8904  else
8905  facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
8906 
8907  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
8908  funval = funvals[gray];
8909  if( overestimate )
8910  error = funval - facetval;
8911  else
8912  error = facetval - funval;
8913 
8914  /* update maximum error */
8915  maxerror = MAX(error, maxerror);
8916 
8917  prev = gray;
8918  }
8919 
8920  SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
8921 
8922  return maxerror;
8923 }
8924 
8925 /** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
8926 static
8928  SCIP* scip, /**< SCIP data structure */
8929  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8930  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
8931  SCIP_Real* xstar, /**< point to be separated */
8932  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
8933  int nallvars, /**< half of the length of box */
8934  int* nonfixedpos, /**< indices of nonfixed variables */
8935  SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
8936  int nvars, /**< number of nonfixed variables */
8937  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
8938  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
8939  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
8940  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
8941  )
8942 { /*lint --e{715}*/
8943  SCIP_CONSHDLRDATA* conshdlrdata;
8944  SCIP_LPI* lp;
8945  SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
8946  int* inds;
8947  int ncols;
8948  int nrows;
8949  int i;
8950  SCIP_Real facetvalue;
8951  SCIP_Real mindomwidth;
8952  SCIP_RETCODE lpsolveretcode;
8953 
8954  assert(scip != NULL);
8955  assert(conshdlr != NULL);
8956  assert(xstar != NULL);
8957  assert(box != NULL);
8958  assert(nonfixedpos != NULL);
8959  assert(funvals != NULL);
8960  assert(nvars >= 0);
8961  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8962  assert(success != NULL);
8963  assert(facetcoefs != NULL);
8964  assert(facetconstant != NULL);
8965 
8966  *success = FALSE;
8967 
8968  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8969  assert(conshdlrdata != NULL);
8970 
8971  if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
8972  {
8973  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
8974  }
8975 
8976  /* construct an LP for this size, if not having one already */
8977  if( conshdlrdata->vp_lp[nvars] == NULL )
8978  {
8979  SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
8980  }
8981  lp = conshdlrdata->vp_lp[nvars];
8982  assert(lp != NULL);
8983 
8984  /* get number of cols and rows of separation lp */
8985  SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
8986  SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
8987 
8988  /* number of columns should equal the number of corners = 2^nvars */
8989  assert(ncols == (int)POWEROFTWO(nvars));
8990 
8991  /* allocate necessary memory */
8992  SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
8993  SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
8994 
8995  /*
8996  * set up the described LP on the transformed space
8997  */
8998 
8999  for( i = 0; i < ncols; ++i )
9000  inds[i] = i;
9001 
9002  /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9003  mindomwidth = 2*SCIPinfinity(scip);
9004  for( i = 0; i < nrows-1; ++i )
9005  {
9006  SCIP_Real solval;
9007  SCIP_Real lb;
9008  SCIP_Real ub;
9009  int varpos;
9010 
9011  assert(i < nvars);
9012 
9013  varpos = nonfixedpos[i];
9014  lb = box[2 * varpos];
9015  ub = box[2 * varpos + 1];
9016  solval = xstar[varpos];
9017 
9018  if( ub - lb < mindomwidth )
9019  mindomwidth = ub - lb;
9020 
9021  /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9022  if( solval <= lb )
9023  aux[i] = 0.0;
9024  else if( solval >= ub )
9025  aux[i] = 1.0;
9026  else
9027  aux[i] = (solval - lb) / (ub - lb);
9028 
9029  /* perturb point to hopefully obtain a facet of the convex envelope */
9030  if( conshdlrdata->vp_maxperturb > 0.0 )
9031  {
9032  assert(conshdlrdata->vp_randnumgen != NULL);
9033 
9034  if( aux[i] == 1.0 )
9035  aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9036  else if( aux[i] == 0.0 )
9037  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9038  else
9039  {
9040  SCIP_Real perturbation;
9041 
9042  perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9043  perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9044  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9045  }
9046  assert(0.0 < aux[i] && aux[i] < 1.0);
9047  }
9048 
9049  SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9050  }
9051 
9052  /* update LP */
9053  SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9054  SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9056 
9057  /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9058  if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9059  {
9060  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9061  }
9062  /* set an iteration limit so we do not run forever */
9063  SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPITLIM, 100*ncols) );
9064  /* 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 */
9066  /* since we work with the dual of the LP, dual feastol determines validity of the facet
9067  * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9068  * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9069  */
9070  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, MIN(SCIPfeastol(scip), MAX(SCIPepsilon(scip), mindomwidth * SCIPfeastol(scip)))) );
9071 
9072 #ifdef SCIP_DEBUG
9074 #endif
9075 
9076  /*
9077  * solve the LP and store the resulting facet for the transformed space
9078  */
9079  if( conshdlrdata->vp_dualsimplex )
9080  {
9081  lpsolveretcode = SCIPlpiSolveDual(lp);
9082  }
9083  else
9084  {
9085  lpsolveretcode = SCIPlpiSolvePrimal(lp);
9086  }
9087  if( lpsolveretcode == SCIP_LPERROR )
9088  {
9089  SCIPdebugMsg(scip, "LP error, aborting.\n");
9090  goto CLEANUP;
9091  }
9092  SCIP_CALL( lpsolveretcode );
9093 
9094  /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9095  if( !SCIPlpiIsDualFeasible(lp) )
9096  {
9097  SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9098  goto CLEANUP;
9099  }
9100 
9101  /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9102  * columns than needed, in particular, \bar \beta is the last dual multiplier
9103  */
9104  SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9105 
9106  for( i = 0; i < nvars; ++i )
9107  facetcoefs[nonfixedpos[i]] = aux[i];
9108  /* last dual multiplier is the constant */
9109  *facetconstant = aux[nrows - 1];
9110 
9111 #ifdef SCIP_DEBUG
9112  SCIPdebugMsg(scip, "facet for the transformed problem: ");
9113  for( i = 0; i < nallvars; ++i )
9114  {
9115  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9116  }
9117  SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9118 #endif
9119 
9120  /*
9121  * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9122  */
9123 
9124  SCIPdebugMsg(scip, "facet in orig. space: ");
9125 
9126  facetvalue = 0.0;
9127  for( i = 0; i < nvars; ++i )
9128  {
9129  SCIP_Real lb;
9130  SCIP_Real ub;
9131  int varpos;
9132 
9133  varpos = nonfixedpos[i];
9134  lb = box[2 * varpos];
9135  ub = box[2 * varpos + 1];
9136  assert(!SCIPisEQ(scip, lb, ub));
9137 
9138  /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9139  facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9140 
9141  /* beta = beta_bar - sum_i alpha_i * lb_i */
9142  *facetconstant -= facetcoefs[varpos] * lb;
9143 
9144  /* evaluate */
9145  facetvalue += facetcoefs[varpos] * xstar[varpos];
9146 
9147  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9148  }
9149  SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9150 
9151  /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9152  facetvalue += *facetconstant;
9153 
9154  SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9155 
9156  /* if overestimate, then we want facetvalue < targetvalue
9157  * if underestimate, then we want facetvalue > targetvalue
9158  * if none holds, give up
9159  * so maybe here we should check against the minimal violation
9160  */
9161  if( overestimate == (facetvalue > targetvalue) )
9162  {
9163  SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9164  goto CLEANUP;
9165  }
9166 
9167  /* if we made it until here, then we have a nice facet */
9168  *success = TRUE;
9169 
9170 CLEANUP:
9171  /* free allocated memory */
9172  SCIPfreeBufferArray(scip, &inds);
9173  SCIPfreeBufferArray(scip, &aux);
9174 
9175  return SCIP_OKAY;
9176 }
9177 
9178 /** computes a facet of the convex or concave envelope of a univariant vertex polyhedral function
9179  *
9180  * In other words, compute the line that passes through two given points.
9181  */
9182 static
9184  SCIP* scip, /**< SCIP data structure */
9185  SCIP_Real left, /**< left coordinate */
9186  SCIP_Real right, /**< right coordinate */
9187  SCIP_Real funleft, /**< value of function in left coordinate */
9188  SCIP_Real funright, /**< value of function in right coordinate */
9189  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9190  SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9191  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9192  )
9193 {
9194  assert(scip != NULL);
9195  assert(SCIPisLE(scip, left, right));
9196  assert(!SCIPisInfinity(scip, -left));
9197  assert(!SCIPisInfinity(scip, right));
9198  assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9199  assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9200  assert(success != NULL);
9201  assert(facetcoef != NULL);
9202  assert(facetconstant != NULL);
9203 
9204  *facetcoef = (funright - funleft) / (right - left);
9205  *facetconstant = funleft - *facetcoef * left;
9206 
9207  *success = TRUE;
9208 
9209  return SCIP_OKAY;
9210 }
9211 
9212 /** given three points, constructs coefficient of equation for hyperplane generated by these three points
9213  *
9214  * Three points a, b, and c are given.
9215  * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9216  * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9217  */
9218 static
9220  SCIP* scip, /**< SCIP data structure */
9221  SCIP_Real a1, /**< first coordinate of a */
9222  SCIP_Real a2, /**< second coordinate of a */
9223  SCIP_Real a3, /**< third coordinate of a */
9224  SCIP_Real b1, /**< first coordinate of b */
9225  SCIP_Real b2, /**< second coordinate of b */
9226  SCIP_Real b3, /**< third coordinate of b */
9227  SCIP_Real c1, /**< first coordinate of c */
9228  SCIP_Real c2, /**< second coordinate of c */
9229  SCIP_Real c3, /**< third coordinate of c */
9230  SCIP_Real* alpha, /**< coefficient of first coordinate */
9231  SCIP_Real* beta, /**< coefficient of second coordinate */
9232  SCIP_Real* gamma_, /**< coefficient of third coordinate */
9233  SCIP_Real* delta /**< constant right-hand side */
9234  )
9235 {
9236  assert(scip != NULL);
9237  assert(alpha != NULL);
9238  assert(beta != NULL);
9239  assert(gamma_ != NULL);
9240  assert(delta != NULL);
9241 
9242  *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9243  *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9244  *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9245  *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9246 
9247  /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9248 
9249  if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9250  SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9251  SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9252  {
9253  SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9254  *delta = 0.0;
9255  *alpha = 0.0;
9256  *beta = 0.0;
9257  *gamma_ = 0.0;
9258  return SCIP_OKAY;
9259  }
9260 
9261  /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9262  if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9263  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9264  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9265  {
9266  SCIP_Real m[9];
9267  SCIP_Real rhs[3];
9268  SCIP_Real x[3];
9269  SCIP_Bool success;
9270 
9271  /*
9272  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));
9273  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));
9274  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));
9275  */
9276 
9277  /* initialize matrix column-wise */
9278  m[0] = a1;
9279  m[1] = b1;
9280  m[2] = c1;
9281  m[3] = a2;
9282  m[4] = b2;
9283  m[5] = c2;
9284  m[6] = a3;
9285  m[7] = b3;
9286  m[8] = c3;
9287 
9288  rhs[0] = 1.0;
9289  rhs[1] = 1.0;
9290  rhs[2] = 1.0;
9291 
9292  SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9293 
9294  /* solve the linear problem */
9295  SCIP_CALL( SCIPsolveLinearEquationsIpopt(3, m, rhs, x, &success) );
9296 
9297  *delta = rhs[0];
9298  *alpha = x[0];
9299  *beta = x[1];
9300  *gamma_ = x[2];
9301 
9302  /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9303  * not add a cut to SCIP and that all assertions are trivially fulfilled
9304  */
9305  if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9306  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9307  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9308  {
9309  SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9310  *delta = 0.0;
9311  *alpha = 0.0;
9312  *beta = 0.0;
9313  *gamma_ = 0.0;
9314  }
9315  }
9316 
9317  if( *gamma_ < 0.0 )
9318  {
9319  *alpha = -*alpha;
9320  *beta = -*beta;
9321  *gamma_ = -*gamma_;
9322  *delta = -*delta;
9323  }
9324 
9325  return SCIP_OKAY;
9326 }
9327 
9328 /** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9329 static
9331  SCIP* scip, /**< SCIP data structure */
9332  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9333  SCIP_Real p1[2], /**< first vertex of box */
9334  SCIP_Real p2[2], /**< second vertex of box */
9335  SCIP_Real p3[2], /**< third vertex of box */
9336  SCIP_Real p4[2], /**< forth vertex of box */
9337  SCIP_Real p1val, /**< value in p1 */
9338  SCIP_Real p2val, /**< value in p2 */
9339  SCIP_Real p3val, /**< value in p3 */
9340  SCIP_Real p4val, /**< value in p4 */
9341  SCIP_Real xstar[2], /**< point to be separated */
9342  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9343  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9344  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9345  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9346  )
9347 {
9348  SCIP_Real alpha, beta, gamma_, delta;
9349  SCIP_Real xstarval, candxstarval = 0.0;
9350  int leaveout;
9351 
9352  assert(scip != NULL);
9353  assert(success != NULL);
9354  assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9355  assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9356  assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9357  assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9358  assert(facetcoefs != NULL);
9359  assert(facetconstant != NULL);
9360 
9361  *success = FALSE;
9362 
9363  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9364  if( !overestimate )
9365  {
9366  p1val = -p1val;
9367  p2val = -p2val;
9368  p3val = -p3val;
9369  p4val = -p4val;
9370  targetvalue = -targetvalue;
9371  }
9372 
9373  SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9374  SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9375  SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9376  SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9377 
9378  /* Compute coefficients alpha, beta, gamma (>0), delta such that
9379  * alpha*x + beta*y + gamma*z = delta
9380  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9381  * the fourth corner point lies below this hyperplane.
9382  * 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.,
9383  * alpha*x + beta*y - delta <= -gamma * f(x,y),
9384  * or, equivalently,
9385  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9386  */
9387  for( leaveout = 1; leaveout <= 4; ++leaveout )
9388  {
9389  switch( leaveout)
9390  {
9391  case 1 :
9392  /* get hyperplane through p2, p3, p4 */
9393  SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9394  &alpha, &beta, &gamma_, &delta) );
9395  /* if not underestimating in p1, then go to next candidate */
9396  if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9397  continue;
9398  break;
9399 
9400  case 2 :
9401  /* get hyperplane through p1, p3, p4 */
9402  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9403  &alpha, &beta, &gamma_, &delta) );
9404  /* if not underestimating in p2, then go to next candidate */
9405  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9406  continue;
9407  break;
9408 
9409  case 3 :
9410  /* get hyperplane through p1, p2, p4 */
9411  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9412  &alpha, &beta, &gamma_, &delta) );
9413  /* if not underestimating in p3, then go to next candidate */
9414  if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9415  continue;
9416  break;
9417 
9418  case 4 :
9419  /* get hyperplane through p1, p2, p3 */
9420  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9421  &alpha, &beta, &gamma_, &delta) );
9422  /* if not underestimating in p4, then stop */
9423  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9424  continue;
9425  break;
9426 
9427  default: /* only for lint */
9428  alpha = SCIP_INVALID;
9429  beta = SCIP_INVALID;
9430  gamma_ = SCIP_INVALID;
9431  delta = SCIP_INVALID;
9432  break;
9433  }
9434 
9435  /* check if bad luck: should not happen if numerics are fine */
9436  if( SCIPisZero(scip, gamma_) )
9437  continue;
9438  assert(!SCIPisNegative(scip, gamma_));
9439 
9440  /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9441  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9442  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9443  continue;
9444 
9445  SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9446 
9447  /* value of hyperplane candidate in xstar */
9448  xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9449 
9450  /* if reaching target and first or better than previous candidate, then update */
9451  if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9452  {
9453  /* flip hyperplane */
9454  if( !overestimate )
9455  gamma_ = -gamma_;
9456 
9457  facetcoefs[0] = -alpha/gamma_;
9458  facetcoefs[1] = -beta/gamma_;
9459  *facetconstant = delta/gamma_;
9460 
9461  *success = TRUE;
9462  candxstarval = xstarval;
9463  }
9464  }
9465 
9466  return SCIP_OKAY;
9467 }
9468 
9469 /*
9470  * Callback methods of constraint handler
9471  */
9472 
9473 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
9474 static
9475 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
9476 { /*lint --e{715}*/
9477  SCIP_CONSHDLR* targetconshdlr;
9478  SCIP_CONSHDLRDATA* sourceconshdlrdata;
9479  int i;
9480 
9481  assert(scip != NULL);
9482  assert(conshdlr != NULL);
9483  assert(valid != NULL);
9484  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
9485 
9486  /* create basic data of constraint handler and include it to scip */
9488 
9489  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9490  assert(targetconshdlr != NULL);
9491  assert(targetconshdlr != conshdlr);
9492 
9493  sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
9494  assert(sourceconshdlrdata != NULL);
9495 
9496  /* copy nonlinear handlers */
9497  for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
9498  {
9499  SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
9500  }
9501 
9502  *valid = TRUE;
9503 
9504  return SCIP_OKAY;
9505 }
9506 
9507 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9508 static
9509 SCIP_DECL_CONSFREE(consFreeNonlinear)
9510 { /*lint --e{715}*/
9511  SCIP_CONSHDLRDATA* conshdlrdata;
9512  int i;
9513 
9514  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9515  assert(conshdlrdata != NULL);
9516 
9517  /* free nonlinear handlers */
9518  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9519  {
9520  SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
9521  assert(conshdlrdata->nlhdlrs[i] == NULL);
9522  }
9523  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
9524  conshdlrdata->nlhdlrssize = 0;
9525 
9526  /* free upgrade functions */
9527  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
9528  {
9529  assert(conshdlrdata->consupgrades[i] != NULL);
9530  SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
9531  }
9532  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
9533 
9534  SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
9535 
9536  SCIPqueueFree(&conshdlrdata->reversepropqueue);
9537 
9538  if( conshdlrdata->vp_randnumgen != NULL )
9539  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9540 
9541  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9542  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9543  {
9544  if( conshdlrdata->vp_lp[i] != NULL )
9545  {
9546  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9547  }
9548  }
9549 
9550  assert(conshdlrdata->branchrandnumgen == NULL);
9551 
9552  assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
9553  SCIPhashmapFree(&conshdlrdata->var2expr);
9554 
9555  SCIPfreeBlockMemory(scip, &conshdlrdata);
9556  SCIPconshdlrSetData(conshdlr, NULL);
9557 
9558  return SCIP_OKAY;
9559 }
9560 
9561 
9562 /** initialization method of constraint handler (called after problem was transformed) */
9563 static
9564 SCIP_DECL_CONSINIT(consInitNonlinear)
9565 { /*lint --e{715}*/
9566  SCIP_CONSHDLRDATA* conshdlrdata;
9567  int i;
9568 
9569  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9570  assert(conshdlrdata != NULL);
9571 
9572  /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
9573  conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
9574  /* set to 1 so it is larger than initial value of lastenforound in exprs */
9575  conshdlrdata->enforound = 1;
9576  /* reset numbering for auxiliary variables */
9577  conshdlrdata->auxvarid = 0;
9578 
9579  for( i = 0; i < nconss; ++i )
9580  {
9581  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
9582  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
9583  }
9584 
9585  /* sort nonlinear handlers by detection priority, in decreasing order */
9586  if( conshdlrdata->nnlhdlrs > 1 )
9587  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
9588 
9589  /* get heuristics for later use */
9590  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9591  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9592 
9593  /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
9594  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9595  {
9596  SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
9597  }
9598 
9599  /* reset statistics in constraint handler */
9600  conshdlrdata->nweaksepa = 0;
9601  conshdlrdata->ntightenlp = 0;
9602  conshdlrdata->ndesperatebranch = 0;
9603  conshdlrdata->ndesperatecutoff = 0;
9604  conshdlrdata->ndesperatetightenlp = 0;
9605  conshdlrdata->nforcelp = 0;
9606  SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
9607  conshdlrdata->ncanonicalizecalls = 0;
9608 
9609 #ifdef ENFOLOGFILE
9610  ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
9611 #endif
9612 
9613  return SCIP_OKAY;
9614 }
9615 
9616 
9617 /** deinitialization method of constraint handler (called before transformed problem is freed) */
9618 static
9619 SCIP_DECL_CONSEXIT(consExitNonlinear)
9620 { /*lint --e{715}*/
9621  SCIP_CONSHDLRDATA* conshdlrdata;
9622  SCIP_CONS** consssorted;
9623  int i;
9624 
9625  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9626  assert(conshdlrdata != NULL);
9627 
9628  if( nconss > 0 )
9629  {
9630  /* for better performance of dropVarEvents, we sort by index, descending */
9631  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
9632  SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
9633 
9634  for( i = 0; i < nconss; ++i )
9635  {
9636  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
9637  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
9638  }
9639 
9640  SCIPfreeBufferArray(scip, &consssorted);
9641  }
9642 
9643  conshdlrdata->subnlpheur = NULL;
9644  conshdlrdata->trysolheur = NULL;
9645 
9646  if( conshdlrdata->vp_randnumgen != NULL )
9647  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
9648 
9649  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
9650  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
9651  {
9652  if( conshdlrdata->vp_lp[i] != NULL )
9653  {
9654  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
9655  }
9656  }
9657 
9658  if( conshdlrdata->branchrandnumgen != NULL )
9659  SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
9660 
9661  /* deinitialize nonlinear handlers */
9662  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9663  {
9664  SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
9665  }
9666 
9667  ENFOLOG(
9668  if( enfologfile != NULL )
9669  {
9670  fclose(enfologfile);
9671  enfologfile = NULL;
9672  })
9673 
9674  return SCIP_OKAY;
9675 }
9676 
9677 
9678 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
9679 #ifdef SCIP_DISABLED_CODE
9680 static
9682 { /*lint --e{715}*/
9683  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
9684  SCIPABORT(); /*lint --e{527}*/
9685 
9686  return SCIP_OKAY;
9687 }
9688 #else
9689 #define consInitpreNonlinear NULL
9690 #endif
9691 
9692 
9693 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9694 static
9695 SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
9696 { /*lint --e{715}*/
9697  SCIP_Bool infeasible;
9698 
9699  if( nconss == 0 )
9700  return SCIP_OKAY;
9701 
9702  /* skip some extra work if already known to be infeasible */
9703  if( SCIPgetStatus(scip) == SCIP_STATUS_INFEASIBLE )
9704  return SCIP_OKAY;
9705 
9706  /* simplify constraints and replace common subexpressions */
9707  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
9708 
9709  /* currently SCIP does not offer to communicate this,
9710  * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
9711  * or if a constraint expression became constant
9712  */
9713  assert(!infeasible);
9714 
9715  /* tell SCIP that we have something nonlinear */
9716  SCIPenableNLP(scip);
9717 
9718  return SCIP_OKAY;
9719 }
9720 
9721 
9722 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
9723 static
9724 SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
9725 { /*lint --e{715}*/
9726  SCIP_CONSHDLRDATA* conshdlrdata;
9727  int i;
9728 
9729  /* skip remaining initializations if we have solved already
9730  * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
9731  * assumes nonempty activities in expressions
9732  */
9733  switch( SCIPgetStatus(scip) )
9734  {
9735  case SCIP_STATUS_OPTIMAL:
9737  case SCIP_STATUS_UNBOUNDED:
9738  case SCIP_STATUS_INFORUNBD:
9739  return SCIP_OKAY;
9740  default: ;
9741  } /*lint !e788 */
9742 
9743  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9744  assert(conshdlrdata != NULL);
9745 
9746  /* reset one of the number of detections counter to count only current round */
9747  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
9748  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
9749 
9750  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
9751 
9752  /* catch new solution event */
9753  if( nconss != 0 && conshdlrdata->linearizeheursol != 'o' )
9754  {
9755  SCIP_EVENTHDLR* eventhdlr;
9756 
9757  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9758  assert(eventhdlr != NULL);
9759 
9760  SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
9761  eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9762  }
9763 
9764  /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
9765  if( conshdlrdata->branchpscostweight > 0.0 )
9766  {
9767  SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
9768  if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
9769  {
9770  SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
9771  SCIPABORT();
9772  return SCIP_INVALIDDATA;
9773  }
9774  }
9775 
9776  return SCIP_OKAY;
9777 }
9778 
9779 
9780 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9781 static
9782 SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
9783 { /*lint --e{715}*/
9784  SCIP_CONSHDLRDATA* conshdlrdata;
9785 
9786  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
9787 
9788  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9789  assert(conshdlrdata != NULL);
9790 
9791  /* free hash table for bilinear terms */
9792  SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
9793 
9794  /* reset flag to allow another call of presolSingleLockedVars() after a restart */
9795  conshdlrdata->checkedvarlocks = FALSE;
9796 
9797  /* drop catching new solution event, if catched before */
9798  if( conshdlrdata->newsoleventfilterpos >= 0 )
9799  {
9800  SCIP_EVENTHDLR* eventhdlr;
9801 
9802  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
9803  assert(eventhdlr != NULL);
9804 
9805  SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9806  conshdlrdata->newsoleventfilterpos = -1;
9807  }
9808 
9809  return SCIP_OKAY;
9810 }
9811 
9812 
9813 /** frees specific constraint data */
9814 static
9815 SCIP_DECL_CONSDELETE(consDeleteNonlinear)
9816 { /*lint --e{715}*/
9817  assert(consdata != NULL);
9818  assert(*consdata != NULL);
9819  assert((*consdata)->expr != NULL);
9820 
9821  /* constraint locks should have been removed */
9822  assert((*consdata)->nlockspos == 0);
9823  assert((*consdata)->nlocksneg == 0);
9824 
9825  /* free variable expressions */
9826  SCIP_CALL( freeVarExprs(scip, *consdata) );
9827 
9828  SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
9829 
9830  /* free nonlinear row representation */
9831  if( (*consdata)->nlrow != NULL )
9832  {
9833  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
9834  }
9835 
9836  SCIPfreeBlockMemory(scip, consdata);
9837 
9838  return SCIP_OKAY;
9839 }
9840 
9841 
9842 /** transforms constraint data into data belonging to the transformed problem */
9843 static
9844 SCIP_DECL_CONSTRANS(consTransNonlinear)
9845 { /*lint --e{715}*/
9846  SCIP_EXPR* targetexpr;
9847  SCIP_CONSDATA* sourcedata;
9848 
9849  sourcedata = SCIPconsGetData(sourcecons);
9850  assert(sourcedata != NULL);
9851 
9852  /* get a copy of sourceexpr with transformed vars */
9853  SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
9854  assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
9855 
9856  /* create transformed cons (only captures targetexpr, no need to copy again) */
9857  SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
9858  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
9859  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
9860  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
9861  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
9862  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
9863 
9864  /* release target expr */
9865  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
9866 
9867  return SCIP_OKAY;
9868 }
9869 
9870 
9871 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9872 static
9873 SCIP_DECL_CONSINITLP(consInitlpNonlinear)
9874 { /*lint --e{715}*/
9875  /* create auxiliary variables and call separation initialization callbacks of the expression handlers
9876  * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
9877  * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
9878  * for now, there is an assert in detectNlhdlrs to require initial if separated
9879  */
9880  SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
9881 
9882  /* collect all bilinear terms for which an auxvar is present
9883  * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
9884  * addition (and removal?) of constraints during solve
9885  * this is typically the majority of constraints, but the method should be made more flexible
9886  */
9887  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
9888 
9889  return SCIP_OKAY;
9890 }
9891 
9892 
9893 /** separation method of constraint handler for LP solutions */
9894 static
9895 SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
9896 { /*lint --e{715}*/
9897  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
9898 
9899  return SCIP_OKAY;
9900 }
9901 
9902 
9903 /** separation method of constraint handler for arbitrary primal solutions */
9904 static
9905 SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
9906 { /*lint --e{715}*/
9907  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
9908 
9909  return SCIP_OKAY;
9910 }
9911 
9912 
9913 /** constraint enforcing method of constraint handler for LP solutions */
9914 static
9915 SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
9916 { /*lint --e{715}*/
9917  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
9918 
9919  return SCIP_OKAY;
9920 }
9921 
9922 
9923 /** constraint enforcing method of constraint handler for relaxation solutions */
9924 static
9925 SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
9926 { /*lint --e{715}*/
9927  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
9928 
9929  return SCIP_OKAY;
9930 }
9931 
9932 
9933 /** constraint enforcing method of constraint handler for pseudo solutions */
9934 static
9935 SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
9936 { /*lint --e{715}*/
9937  SCIP_RESULT propresult;
9938  SCIP_Longint soltag;
9939  int nchgbds;
9940  int nnotify;
9941  int c;
9942 
9943  soltag = SCIPgetExprNewSoltag(scip);
9944 
9945  *result = SCIP_FEASIBLE;
9946  for( c = 0; c < nconss; ++c )
9947  {
9948  SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
9949 
9950  if( isConsViolated(scip, conss[c]) )
9951  *result = SCIP_INFEASIBLE;
9952  }
9953 
9954  if( *result == SCIP_FEASIBLE )
9955  return SCIP_OKAY;
9956 
9957  /* try to propagate
9958  * TODO obey propinenfo parameter, but we need something to recognize cutoff
9959  */
9960  nchgbds = 0;
9961  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
9962 
9963  if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
9964  {
9965  *result = propresult;
9966  return SCIP_OKAY;
9967  }
9968 
9969  /* register all unfixed variables in all violated constraints as branching candidates */
9970  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
9971  if( nnotify > 0 )
9972  {
9973  SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
9974 
9975  return SCIP_OKAY;
9976  }
9977 
9978  SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
9979  *result = SCIP_SOLVELP;
9980  ++SCIPconshdlrGetData(conshdlr)->nforcelp;
9981 
9982  return SCIP_OKAY;
9983 }
9984 
9985 
9986 /** feasibility check method of constraint handler for integral solutions */
9987 static
9988 SCIP_DECL_CONSCHECK(consCheckNonlinear)
9989 { /*lint --e{715}*/
9990  SCIP_CONSHDLRDATA* conshdlrdata;
9991  SCIP_CONSDATA* consdata;
9992  SCIP_Real maxviol;
9993  SCIP_Bool maypropfeasible;
9994  SCIP_Longint soltag;
9995  int c;
9996 
9997  assert(scip != NULL);
9998  assert(conshdlr != NULL);
9999  assert(conss != NULL || nconss == 0);
10000  assert(result != NULL);
10001 
10002  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10003  assert(conshdlrdata != NULL);
10004 
10005  *result = SCIP_FEASIBLE;
10006  soltag = SCIPgetExprNewSoltag(scip);
10007  maxviol = 0.0;
10008  maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
10009  && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING;
10010 
10011  /* check nonlinear constraints for feasibility */
10012  for( c = 0; c < nconss; ++c )
10013  {
10014  assert(conss != NULL && conss[c] != NULL);
10015  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
10016 
10017  if( isConsViolated(scip, conss[c]) )
10018  {
10019  *result = SCIP_INFEASIBLE;
10020  maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
10021 
10022  consdata = SCIPconsGetData(conss[c]);
10023  assert(consdata != NULL);
10024 
10025  /* print reason for infeasibility */
10026  if( printreason )
10027  {
10028  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
10029  SCIPinfoMessage(scip, NULL, ";\n");
10030 
10031  if( consdata->lhsviol > SCIPfeastol(scip) )
10032  {
10033  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
10034  }
10035  if( consdata->rhsviol > SCIPfeastol(scip) )
10036  {
10037  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
10038  }
10039  }
10040  else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
10041  {
10042  /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
10043  return SCIP_OKAY;
10044  }
10045 
10046  /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
10047  if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
10048  maypropfeasible = FALSE;
10049 
10050  if( maypropfeasible )
10051  {
10052  if( consdata->lhsviol > SCIPfeastol(scip) )
10053  {
10054  /* check if there is a variable which may help to get the left hand side satisfied
10055  * if there is no such variable, then we cannot get feasible
10056  */
10057  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
10058  !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
10059  maypropfeasible = FALSE;
10060  }
10061  else
10062  {
10063  assert(consdata->rhsviol > SCIPfeastol(scip));
10064  /* check if there is a variable which may help to get the right hand side satisfied
10065  * if there is no such variable, then we cannot get feasible
10066  */
10067  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
10068  !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
10069  maypropfeasible = FALSE;
10070  }
10071  }
10072  }
10073  }
10074 
10075  if( *result == SCIP_INFEASIBLE && maypropfeasible )
10076  {
10077  SCIP_Bool success;
10078 
10079  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
10080 
10081  /* do not pass solution to NLP heuristic if we made it feasible this way */
10082  if( success )
10083  return SCIP_OKAY;
10084  }
10085 
10086  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
10087  {
10088  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
10089  }
10090 
10091  return SCIP_OKAY;
10092 }
10093 
10094 
10095 /** domain propagation method of constraint handler */
10096 static
10097 SCIP_DECL_CONSPROP(consPropNonlinear)
10098 { /*lint --e{715}*/
10099  int nchgbds = 0;
10100 
10101  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
10102  assert(nchgbds >= 0);
10103 
10104  /* TODO would it make sense to check for redundant constraints? */
10105 
10106  return SCIP_OKAY;
10107 }
10108 
10109 
10110 /** presolving method of constraint handler */
10111 static
10112 SCIP_DECL_CONSPRESOL(consPresolNonlinear)
10113 { /*lint --e{715}*/
10114  SCIP_CONSHDLRDATA* conshdlrdata;
10115  SCIP_Bool infeasible;
10116  int c;
10117 
10118  *result = SCIP_DIDNOTFIND;
10119 
10120  if( nconss == 0 )
10121  {
10122  *result = SCIP_DIDNOTRUN;
10123  return SCIP_OKAY;
10124  }
10125 
10126  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10127  assert(conshdlrdata != NULL);
10128 
10129  /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
10130  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
10131  if( infeasible )
10132  {
10133  *result = SCIP_CUTOFF;
10134  return SCIP_OKAY;
10135  }
10136 
10137  /* merge constraints with the same root expression */
10138  if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
10139  {
10140  SCIP_Bool success;
10141 
10142  SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
10143  if( success )
10144  *result = SCIP_SUCCESS;
10145  }
10146 
10147  /* propagate constraints */
10148  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
10149  if( *result == SCIP_CUTOFF )
10150  return SCIP_OKAY;
10151 
10152  /* propagate function domains (TODO integrate with simplify?) */
10153  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
10154  {
10155  SCIP_RESULT localresult;
10156  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
10157  if( localresult == SCIP_CUTOFF )
10158  {
10159  *result = SCIP_CUTOFF;
10160  return SCIP_OKAY;
10161  }
10162  if( localresult == SCIP_REDUCEDDOM )
10163  *result = SCIP_REDUCEDDOM;
10164  }
10165 
10166  /* check for redundant constraints, remove constraints that are a value expression */
10167  SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
10168  if( infeasible )
10169  {
10170  *result = SCIP_CUTOFF;
10171  return SCIP_OKAY;
10172  }
10173 
10174  /* try to upgrade constraints */
10175  for( c = 0; c < nconss; ++c )
10176  {
10177  SCIP_Bool upgraded;
10178 
10179  /* skip inactive and deleted constraints */
10180  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
10181  continue;
10182 
10183  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10184  }
10185 
10186  /* try to change continuous variables that appear linearly to be implicit integer */
10187  if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
10188  {
10189  SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
10190 
10191  if( infeasible )
10192  {
10193  SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
10194  *result = SCIP_CUTOFF;
10195  return SCIP_OKAY;
10196  }
10197  }
10198 
10199  /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
10200  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) && SCIPisPresolveFinished(scip)
10201  && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
10202  {
10203  /* run this presolving technique only once because we don't want to generate identical bound disjunction
10204  * constraints multiple times
10205  */
10206  conshdlrdata->checkedvarlocks = TRUE;
10207 
10208  for( c = 0; c < nconss; ++c )
10209  {
10210  int tmpnchgvartypes = 0;
10211  int tmpnaddconss = 0;
10212 
10213  SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
10214  SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
10215  SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
10216 
10217  if( infeasible )
10218  {
10219  SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
10220  *result = SCIP_CUTOFF;
10221  return SCIP_OKAY;
10222  }
10223 
10224  (*nchgvartypes) += tmpnchgvartypes;
10225  (*naddconss) += tmpnaddconss;
10226  }
10227  }
10228 
10229  if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
10230  *result = SCIP_SUCCESS;
10231  else
10232  *result = SCIP_DIDNOTFIND;
10233 
10234  return SCIP_OKAY;
10235 }
10236 
10237 
10238 /** propagation conflict resolving method of constraint handler */
10239 #ifdef SCIP_DISABLED_CODE
10240 static
10242 { /*lint --e{715}*/
10243  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10244  SCIPABORT(); /*lint --e{527}*/
10245 
10246  return SCIP_OKAY;
10247 }
10248 #else
10249 #define consRespropNonlinear NULL
10250 #endif
10251 
10252 
10253 /** variable rounding lock method of constraint handler */
10254 static
10255 SCIP_DECL_CONSLOCK(consLockNonlinear)
10256 { /*lint --e{715}*/
10257  SCIP_CONSDATA* consdata;
10258  SCIP_EXPR_OWNERDATA* ownerdata;
10259  SCIP_Bool reinitsolve = FALSE;
10260 
10261  assert(conshdlr != NULL);
10262  assert(cons != NULL);
10263 
10264  consdata = SCIPconsGetData(cons);
10265  assert(consdata != NULL);
10266  assert(consdata->expr != NULL);
10267 
10268  ownerdata = SCIPexprGetOwnerData(consdata->expr);
10269 
10270  /* check whether we need to initSolve again because
10271  * - we have enfo initialized (nenfos >= 0)
10272  * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
10273  */
10274  if( ownerdata->nenfos >= 0 )
10275  {
10276  if( (consdata->nlockspos == 0) != (nlockspos == 0) )
10277  reinitsolve = TRUE;
10278  if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
10279  reinitsolve = TRUE;
10280  }
10281 
10282  if( reinitsolve )
10283  {
10284  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10285  }
10286 
10287  /* add locks */
10288  SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
10289 
10290  if( reinitsolve )
10291  {
10292  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10293  }
10294 
10295  return SCIP_OKAY;
10296 }
10297 
10298 
10299 /** constraint activation notification method of constraint handler */
10300 static
10301 SCIP_DECL_CONSACTIVE(consActiveNonlinear)
10302 { /*lint --e{715}*/
10303  SCIP_CONSDATA* consdata;
10304  SCIP_Bool infeasible = FALSE;
10305 
10306  consdata = SCIPconsGetData(cons);
10307  assert(consdata != NULL);
10308 
10309  /* simplify root expression if the constraint has been added after presolving */
10311  {
10312  SCIP_Bool replacedroot;
10313 
10314  if( !consdata->issimplified )
10315  {
10316  SCIP_EXPR* simplified;
10317  SCIP_Bool changed;
10318 
10319  /* simplify constraint */
10320  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
10321  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
10322  assert(simplified != NULL);
10323  consdata->expr = simplified;
10324  consdata->issimplified = TRUE;
10325  }
10326 
10327  /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
10328  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
10329  assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
10330 
10331  /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
10332  {
10333  SCIP_CONSHDLRDATA* conshdlrdata;
10334  SCIP_EXPRITER* it;
10335  SCIP_EXPR* expr;
10336 
10337  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10338  assert(conshdlrdata != NULL);
10339 
10340  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
10341  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
10343  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10344  {
10345  SCIP_EXPR* child;
10346  SCIP_EXPR* hashmapexpr;
10347 
10348  child = SCIPexpriterGetChildExprDFS(it);
10349  if( !SCIPisExprVar(scip, child) )
10350  continue;
10351 
10352  /* check which expression is stored in the hashmap for the var of child */
10353  hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
10354  /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
10355  if( hashmapexpr != NULL && hashmapexpr != child )
10356  {
10357  SCIP_CALL( SCIPreplaceExprChild(scip, expr, SCIPexpriterGetChildIdxDFS(it), hashmapexpr) );
10358  }
10359  }
10360  SCIPfreeExpriter(&it);
10361  }
10362  }
10363 
10364  /* store variable expressions */
10365  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10366  {
10367  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10368  }
10369 
10370  /* add manually locks to constraints that are not checked for feasibility */
10371  if( !SCIPconsIsChecked(cons) )
10372  {
10373  assert(consdata->nlockspos == 0);
10374  assert(consdata->nlocksneg == 0);
10375 
10376  SCIP_CALL( addLocks(scip, cons, 1, 0) );
10377  }
10378 
10379  if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
10380  {
10381  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
10382  }
10383 
10384  /* TODO deal with infeasibility */
10385  assert(!infeasible);
10386 
10387  return SCIP_OKAY;
10388 }
10389 
10390 
10391 /** constraint deactivation notification method of constraint handler */
10392 static
10393 SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
10394 { /*lint --e{715}*/
10395  SCIP_CONSHDLRDATA* conshdlrdata;
10396 
10397  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10398  assert(conshdlrdata != NULL);
10399 
10400  if( SCIPgetStage(scip) < SCIP_STAGE_EXITSOLVE )
10401  {
10402  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
10403  }
10404 
10405  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
10406  {
10407  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10408  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(cons)) );
10409  }
10410 
10411  /* remove locks that have been added in consActiveExpr() */
10412  if( !SCIPconsIsChecked(cons) )
10413  {
10414  SCIP_CALL( addLocks(scip, cons, -1, 0) );
10415 
10416  assert(SCIPconsGetData(cons)->nlockspos == 0);
10417  assert(SCIPconsGetData(cons)->nlocksneg == 0);
10418  }
10419 
10420  return SCIP_OKAY;
10421 }
10422 
10423 
10424 /** constraint enabling notification method of constraint handler */
10425 static
10426 SCIP_DECL_CONSENABLE(consEnableNonlinear)
10427 { /*lint --e{715}*/
10428  SCIP_CONSHDLRDATA* conshdlrdata;
10429 
10430  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10431  assert(conshdlrdata != NULL);
10432 
10433  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10434  {
10435  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10436  }
10437 
10438  return SCIP_OKAY;
10439 }
10440 
10441 
10442 /** constraint disabling notification method of constraint handler */
10443 static
10444 SCIP_DECL_CONSDISABLE(consDisableNonlinear)
10445 { /*lint --e{715}*/
10446  SCIP_CONSHDLRDATA* conshdlrdata;
10447 
10448  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10449  assert(conshdlrdata != NULL);
10450 
10451  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
10452  {
10453  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
10454  }
10455 
10456  return SCIP_OKAY;
10457 }
10458 
10459 /** variable deletion of constraint handler */
10460 #ifdef SCIP_DISABLED_CODE
10461 static
10463 { /*lint --e{715}*/
10464  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10465  SCIPABORT(); /*lint --e{527}*/
10466 
10467  return SCIP_OKAY;
10468 }
10469 #else
10470 #define consDelvarsNonlinear NULL
10471 #endif
10472 
10473 
10474 /** constraint display method of constraint handler */
10475 static
10476 SCIP_DECL_CONSPRINT(consPrintNonlinear)
10477 { /*lint --e{715}*/
10478  SCIP_CONSDATA* consdata;
10479 
10480  consdata = SCIPconsGetData(cons);
10481  assert(consdata != NULL);
10482  assert(consdata->expr != NULL);
10483 
10484  /* print left hand side for ranged constraints */
10485  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10486  {
10487  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10488  }
10489 
10490  /* print expression */
10491  SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
10492 
10493  /* print right hand side */
10494  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10495  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
10496  else if( !SCIPisInfinity(scip, consdata->rhs) )
10497  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
10498  else if( !SCIPisInfinity(scip, -consdata->lhs) )
10499  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
10500  else
10501  SCIPinfoMessage(scip, file, " [free]");
10502 
10503  return SCIP_OKAY;
10504 }
10505 
10506 
10507 /** constraint copying method of constraint handler */
10508 static
10509 SCIP_DECL_CONSCOPY(consCopyNonlinear)
10510 { /*lint --e{715}*/
10511  SCIP_CONSHDLR* targetconshdlr;
10512  SCIP_EXPR* targetexpr = NULL;
10513  SCIP_CONSDATA* sourcedata;
10514 
10515  assert(cons != NULL);
10516 
10517  sourcedata = SCIPconsGetData(sourcecons);
10518  assert(sourcedata != NULL);
10519 
10520  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10521  assert(targetconshdlr != NULL);
10522 
10523  SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
10524 
10525  if( targetexpr == NULL )
10526  *valid = FALSE;
10527 
10528  *cons = NULL;
10529  if( *valid )
10530  {
10531  /* create copy (only capture targetexpr, no need to copy again) */
10532  SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
10533  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
10534  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10535  }
10536 
10537  if( targetexpr != NULL )
10538  {
10539  /* release target expr */
10540  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
10541  }
10542 
10543  return SCIP_OKAY;
10544 }
10545 
10546 
10547 /** constraint parsing method of constraint handler */
10548 static
10549 SCIP_DECL_CONSPARSE(consParseNonlinear)
10550 { /*lint --e{715}*/
10551  SCIP_Real lhs;
10552  SCIP_Real rhs;
10553  const char* endptr;
10554  SCIP_EXPR* consexprtree;
10555 
10556  SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
10557 
10558  assert(scip != NULL);
10559  assert(success != NULL);
10560  assert(str != NULL);
10561  assert(name != NULL);
10562  assert(cons != NULL);
10563 
10564  *success = FALSE;
10565 
10566  /* return if string empty */
10567  if( !*str )
10568  return SCIP_OKAY;
10569 
10570  endptr = str;
10571 
10572  /* set left and right hand side to their default values */
10573  lhs = -SCIPinfinity(scip);
10574  rhs = SCIPinfinity(scip);
10575 
10576  /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
10577 
10578  /* check for left hand side */
10579  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
10580  {
10581  /* there is a number coming, maybe it is a left-hand-side */
10582  if( !SCIPstrToRealValue(str, &lhs, (char**)&endptr) )
10583  {
10584  SCIPerrorMessage("error parsing number from <%s>\n", str);
10585  return SCIP_READERROR;
10586  }
10587 
10588  /* ignore whitespace */
10589  while( isspace((unsigned char)*endptr) )
10590  ++endptr;
10591 
10592  if( endptr[0] != '<' || endptr[1] != '=' )
10593  {
10594  /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
10595  lhs = -SCIPinfinity(scip);
10596  }
10597  else
10598  {
10599  /* it was indeed a left-hand-side, so continue parsing after it */
10600  str = endptr + 2;
10601 
10602  /* ignore whitespace */
10603  while( isspace((unsigned char)*str) )
10604  ++str;
10605  }
10606  }
10607 
10608  SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
10609 
10610  /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
10611  SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
10612 
10613  /* check for left or right hand side */
10614  while( isspace((unsigned char)*str) )
10615  ++str;
10616 
10617  /* check for free constraint */
10618  if( strncmp(str, "[free]", 6) == 0 )
10619  {
10620  if( !SCIPisInfinity(scip, -lhs) )
10621  {
10622  SCIPerrorMessage("cannot have left hand side and [free] status \n");
10623  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10624  return SCIP_OKAY;
10625  }
10626  *success = TRUE;
10627  }
10628  else
10629  {
10630  switch( *str )
10631  {
10632  case '<':
10633  *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10634  break;
10635  case '=':
10636  if( !SCIPisInfinity(scip, -lhs) )
10637  {
10638  SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
10639  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10640  return SCIP_OKAY;
10641  }
10642  else
10643  {
10644  *success = SCIPstrToRealValue(str+2, &rhs, (char**)&endptr);
10645  lhs = rhs;
10646  }
10647  break;
10648  case '>':
10649  if( !SCIPisInfinity(scip, -lhs) )
10650  {
10651  SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
10652  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10653  return SCIP_OKAY;
10654  }
10655  else
10656  {
10657  *success = SCIPstrToRealValue(str+2, &lhs, (char**)&endptr);
10658  break;
10659  }
10660  case '\0':
10661  *success = TRUE;
10662  break;
10663  default:
10664  SCIPerrorMessage("unexpected character %c\n", *str);
10665  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10666  return SCIP_OKAY;
10667  }
10668  }
10669 
10670  /* create constraint */
10671  SCIP_CALL( createCons(scip, conshdlr, cons, name,
10672  consexprtree, lhs, rhs, FALSE,
10673  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
10674  assert(*cons != NULL);
10675 
10676  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
10677 
10678  SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
10679 
10680  return SCIP_OKAY;
10681 }
10682 
10683 
10684 /** constraint method of constraint handler which returns the variables (if possible) */
10685 static
10686 SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
10687 { /*lint --e{715}*/
10688  SCIP_CONSDATA* consdata;
10689  int i;
10690 
10691  consdata = SCIPconsGetData(cons);
10692  assert(consdata != NULL);
10693 
10694  /* store variable expressions if not done so far */
10695  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10696 
10697  /* check whether array is too small in order to store all variables */
10698  if( varssize < consdata->nvarexprs )
10699  {
10700  *success = FALSE;
10701  return SCIP_OKAY;
10702  }
10703 
10704  for( i = 0; i < consdata->nvarexprs; ++i )
10705  {
10706  vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
10707  assert(vars[i] != NULL);
10708  }
10709 
10710  *success = TRUE;
10711 
10712  return SCIP_OKAY;
10713 }
10714 
10715 /** constraint method of constraint handler which returns the number of variables (if possible) */
10716 static
10717 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
10718 { /*lint --e{715}*/
10719  SCIP_CONSDATA* consdata;
10720 
10721  consdata = SCIPconsGetData(cons);
10722  assert(consdata != NULL);
10723 
10724  /* store variable expressions if not done so far */
10725  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
10726 
10727  *nvars = consdata->nvarexprs;
10728  *success = TRUE;
10729 
10730  return SCIP_OKAY;
10731 }
10732 
10733 /** constraint handler method to suggest dive bound changes during the generic diving algorithm */
10734 #ifdef SCIP_DISABLED_CODE
10735 static
10737 { /*lint --e{715}*/
10738  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
10739  SCIPABORT(); /*lint --e{527}*/
10740 
10741  return SCIP_OKAY;
10742 }
10743 #else
10744 #define consGetDiveBdChgsNonlinear NULL
10745 #endif
10746 
10747 /** output method of statistics table to output file stream 'file' */
10748 static
10749 SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
10750 { /*lint --e{715}*/
10751  SCIP_CONSHDLR* conshdlr;
10752  SCIP_CONSHDLRDATA* conshdlrdata;
10753 
10754  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10755  assert(conshdlr != NULL);
10756 
10757  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10758  assert(conshdlrdata != NULL);
10759 
10760  /* print statistics for constraint handler */
10761  SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
10762  SCIPinfoMessage(scip, file, " enforce%-10s:", "");
10763  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
10764  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
10765  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
10766  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
10767  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
10768  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
10769  SCIPinfoMessage(scip, file, "\n");
10770  SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
10771  SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
10772  SCIPinfoMessage(scip, file, "\n");
10773 
10774  return SCIP_OKAY;
10775 }
10776 
10777 /** output method of statistics table to output file stream 'file' */
10778 static
10779 SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
10780 { /*lint --e{715}*/
10781  SCIP_CONSHDLR* conshdlr;
10782  SCIP_CONSHDLRDATA* conshdlrdata;
10783 
10784  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10785  assert(conshdlr != NULL);
10786 
10787  /* skip nlhdlr table if there never were active nonlinear constraints */
10788  if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
10789  return SCIP_OKAY;
10790 
10791  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10792  assert(conshdlrdata != NULL);
10793 
10794  /* print statistics for nonlinear handlers */
10795  SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
10796 
10797  return SCIP_OKAY;
10798 }
10799 
10800 /** execution method of display nlhdlrs dialog */
10801 static
10802 SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
10803 { /*lint --e{715}*/
10804  SCIP_CONSHDLR* conshdlr;
10805  SCIP_CONSHDLRDATA* conshdlrdata;
10806  int i;
10807 
10808  /* add dialog to history of dialogs that have been executed */
10809  SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
10810 
10811  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10812  assert(conshdlr != NULL);
10813 
10814  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10815  assert(conshdlrdata != NULL);
10816 
10817  /* display list of nonlinear handler */
10818  SCIPdialogMessage(scip, NULL, "\n");
10819  SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
10820  SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
10821  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10822  {
10823  SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
10824  assert(nlhdlr != NULL);
10825 
10826  SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
10827  SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
10828  SCIPdialogMessage(scip, NULL, " %10d ", SCIPnlhdlrGetDetectPriority(nlhdlr));
10829  SCIPdialogMessage(scip, NULL, " %11d ", SCIPnlhdlrGetEnfoPriority(nlhdlr));
10830  SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
10831  SCIPdialogMessage(scip, NULL, "\n");
10832  }
10833  SCIPdialogMessage(scip, NULL, "\n");
10834 
10835  /* next dialog will be root dialog again */
10836  *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
10837 
10838  return SCIP_OKAY;
10839 }
10840 
10841 /*
10842  * constraint handler specific interface methods
10843  */
10844 
10845 /** creates the handler for nonlinear constraints and includes it in SCIP */
10847  SCIP* scip /**< SCIP data structure */
10848  )
10849 {
10850  SCIP_CONSHDLRDATA* conshdlrdata;
10851  SCIP_DIALOG* parentdialog;
10852 
10853  /* create nonlinear constraint handler data */
10854  SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
10855  conshdlrdata->intevalvar = intEvalVarBoundTightening;
10856  conshdlrdata->curboundstag = 1;
10857  conshdlrdata->lastboundrelax = 1;
10858  conshdlrdata->curpropboundstag = 1;
10859  conshdlrdata->newsoleventfilterpos = -1;
10860  SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
10861  SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
10862  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
10863 
10864  /* include constraint handler */
10870  conshdlrCopyNonlinear,
10871  consFreeNonlinear, consInitNonlinear, consExitNonlinear,
10872  consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
10873  consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
10874  consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
10875  consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
10876  consActiveNonlinear, consDeactiveNonlinear,
10877  consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
10878  consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
10879  consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, conshdlrdata) );
10880 
10881  /* add nonlinear constraint handler parameters */
10882  /* TODO organize into more subcategories */
10883  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
10884  "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
10885  &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
10886 
10887  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
10888  "whether to check bounds of all auxiliary variable to seed reverse propagation",
10889  &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
10890 
10891  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
10892  "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",
10893  &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
10894 
10895  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
10896  "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
10897  &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10898 
10899  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
10900  "by how much to relax constraint sides during bound tightening",
10901  &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
10902 
10903  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
10904  "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
10905  &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
10906 
10907  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
10908  "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
10909  &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
10910 
10911  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
10912  "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
10913  &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
10914 
10915  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
10916  "maximal number of auxiliary expressions per bilinear term",
10917  &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
10918 
10919  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
10920  "whether to reformulate products of binary variables during presolving",
10921  &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
10922 
10923  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
10924  "whether to use the AND constraint handler for reformulating binary products",
10925  &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
10926 
10927  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
10928  "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
10929  &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
10930 
10931  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
10932  "whether to forbid multiaggregation of nonlinear variables",
10933  &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
10934 
10935  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
10936  "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
10937  &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
10938 
10939  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
10940  "whether to (re)run propagation in enforcement",
10941  &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
10942 
10943  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
10944  "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
10945  &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
10946 
10947  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
10948  "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
10949  &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
10950 
10951  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
10952  "consider efficacy requirement when deciding whether a cut is \"strong\"",
10953  &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
10954 
10955  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
10956  "whether to force \"strong\" cuts in enforcement",
10957  &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
10958 
10959  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
10960  "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
10961  &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
10962 
10963  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
10964  "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
10965  &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
10966 
10967  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
10968  "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",
10969  &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
10970 
10971  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
10972  "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
10973  &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
10974 
10975  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
10976  "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)",
10977  &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
10978 
10979  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
10980  "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
10981  &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
10982 
10983  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
10984  "whether to use external branching candidates and branching rules for branching",
10985  &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
10986 
10987  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
10988  "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
10989  &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
10990 
10991  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
10992  "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
10993  &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
10994 
10995  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
10996  "weight by how much to consider the violation assigned to a variable for its branching score",
10997  &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
10998 
10999  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
11000  "weight by how much to consider the dual values of rows that contain a variable for its branching score",
11001  &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11002 
11003  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
11004  "weight by how much to consider the pseudo cost of a variable for its branching score",
11005  &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11006 
11007  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
11008  "weight by how much to consider the domain width in branching score",
11009  &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11010 
11011  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
11012  "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
11013  &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
11014 
11015  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
11016  "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
11017  &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
11018 
11019  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
11020  "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
11021  &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
11022 
11023  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
11024  "minimum pseudo-cost update count required to consider pseudo-costs reliable",
11025  &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
11026 
11027  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
11028  "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)",
11029  &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
11030 
11031  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
11032  "whether to assume that any constraint is convex",
11033  &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
11034 
11035  /* include handler for bound change events */
11036  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
11037  "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
11038  assert(conshdlrdata->eventhdlr != NULL);
11039 
11040  /* include tables for statistics */
11041  assert(SCIPfindTable(scip, TABLE_NAME_NONLINEAR) == NULL);
11043  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
11045 
11046  assert(SCIPfindTable(scip, TABLE_NAME_NLHDLR) == NULL);
11048  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
11050 
11051  /* create, include, and release display nlhdlrs dialog */
11052  if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
11053  {
11054  SCIP_DIALOG* dialog;
11055 
11056  assert(parentdialog != NULL);
11057  assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
11058 
11059  SCIP_CALL( SCIPincludeDialog(scip, &dialog,
11060  NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
11062  SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
11063  SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
11064  }
11065 
11066  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
11067  processNewSolutionEvent, NULL) );
11068 
11069  return SCIP_OKAY;
11070 }
11071 
11072 /** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
11074  SCIP* scip, /**< SCIP data structure */
11075  SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
11076  int priority, /**< priority of upgrading method */
11077  SCIP_Bool active, /**< should the upgrading method by active by default? */
11078  const char* conshdlrname /**< name of the constraint handler */
11079  )
11080 {
11081  SCIP_CONSHDLR* conshdlr;
11082  SCIP_CONSHDLRDATA* conshdlrdata;
11083  CONSUPGRADE* consupgrade;
11084  char paramname[SCIP_MAXSTRLEN];
11085  char paramdesc[SCIP_MAXSTRLEN];
11086  int i;
11087 
11088  assert(conshdlrname != NULL );
11089  assert(nlconsupgd != NULL);
11090 
11091  /* find the nonlinear constraint handler */
11092  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11093  if( conshdlr == NULL )
11094  {
11095  SCIPerrorMessage("nonlinear constraint handler not found\n");
11096  return SCIP_PLUGINNOTFOUND;
11097  }
11098 
11099  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11100  assert(conshdlrdata != NULL);
11101 
11102  /* check whether upgrade method exists already */
11103  for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
11104  {
11105  if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
11106  {
11107 #ifdef SCIP_DEBUG
11108  SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
11109 #endif
11110  return SCIP_OKAY;
11111  }
11112  }
11113 
11114  /* create a nonlinear constraint upgrade data object */
11115  SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
11116  consupgrade->consupgd = nlconsupgd;
11117  consupgrade->priority = priority;
11118  consupgrade->active = active;
11119 
11120  /* insert nonlinear constraint upgrade method into constraint handler data */
11121  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
11122  assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
11123 
11124  for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
11125  conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
11126  assert(0 <= i && i <= conshdlrdata->nconsupgrades);
11127  conshdlrdata->consupgrades[i] = consupgrade;
11128  conshdlrdata->nconsupgrades++;
11129 
11130  /* adds parameter to turn on and off the upgrading step */
11131  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
11132  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
11134  paramname, paramdesc,
11135  &consupgrade->active, FALSE, active, NULL, NULL) );
11136 
11137  return SCIP_OKAY;
11138 }
11139 
11140 /** creates and captures a nonlinear constraint
11141  *
11142  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11143  */
11145  SCIP* scip, /**< SCIP data structure */
11146  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11147  const char* name, /**< name of constraint */
11148  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11149  SCIP_Real lhs, /**< left hand side of constraint */
11150  SCIP_Real rhs, /**< right hand side of constraint */
11151  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11152  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11153  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11154  * Usually set to TRUE. */
11155  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11156  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11157  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11158  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11159  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11160  * Usually set to TRUE. */
11161  SCIP_Bool local, /**< is constraint only valid locally?
11162  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11163  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11164  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11165  * adds coefficients to this constraint. */
11166  SCIP_Bool dynamic, /**< is constraint subject to aging?
11167  * Usually set to FALSE. Set to TRUE for own cuts which
11168  * are separated as constraints. */
11169  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11170  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11171  )
11172 {
11173  /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
11174  SCIP_CONSHDLR* conshdlr;
11175 
11176  /* find the nonlinear constraint handler */
11177  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11178  if( conshdlr == NULL )
11179  {
11180  SCIPerrorMessage("nonlinear constraint handler not found\n");
11181  return SCIP_PLUGINNOTFOUND;
11182  }
11183 
11184  /* create constraint */
11185  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
11186  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11187 
11188  return SCIP_OKAY;
11189 }
11190 
11191 /** creates and captures a nonlinear constraint with all its constraint flags set to their default values
11192  *
11193  * All flags can be set via SCIPconsSetFLAGNAME-methods.
11194  *
11195  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
11196  *
11197  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11198  */
11200  SCIP* scip, /**< SCIP data structure */
11201  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11202  const char* name, /**< name of constraint */
11203  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
11204  SCIP_Real lhs, /**< left hand side of constraint */
11205  SCIP_Real rhs /**< right hand side of constraint */
11206  )
11207 {
11208  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
11209  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11210 
11211  return SCIP_OKAY;
11212 }
11213 
11214 /** creates and captures a quadratic nonlinear constraint
11215  *
11216  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11217  */
11219  SCIP* scip, /**< SCIP data structure */
11220  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11221  const char* name, /**< name of constraint */
11222  int nlinvars, /**< number of linear terms */
11223  SCIP_VAR** linvars, /**< array with variables in linear part */
11224  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11225  int nquadterms, /**< number of quadratic terms */
11226  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11227  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11228  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11229  SCIP_Real lhs, /**< left hand side of quadratic equation */
11230  SCIP_Real rhs, /**< right hand side of quadratic equation */
11231  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11232  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11233  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11234  * Usually set to TRUE. */
11235  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11236  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11237  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11238  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11239  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11240  * Usually set to TRUE. */
11241  SCIP_Bool local, /**< is constraint only valid locally?
11242  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11243  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11244  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11245  * adds coefficients to this constraint. */
11246  SCIP_Bool dynamic, /**< is constraint subject to aging?
11247  * Usually set to FALSE. Set to TRUE for own cuts which
11248  * are separated as constraints. */
11249  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11250  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11251  )
11252 {
11253  SCIP_CONSHDLR* conshdlr;
11254  SCIP_EXPR* expr;
11255 
11256  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
11257  assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
11258 
11259  /* get nonlinear constraint handler */
11260  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11261  if( conshdlr == NULL )
11262  {
11263  SCIPerrorMessage("nonlinear constraint handler not found\n");
11264  return SCIP_PLUGINNOTFOUND;
11265  }
11266 
11267  /* create quadratic expression */
11268  SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
11269  assert(expr != NULL);
11270 
11271  /* create nonlinear constraint */
11272  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
11273  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11274 
11275  /* release quadratic expression (captured by constraint now) */
11276  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11277 
11278  return SCIP_OKAY;
11279 }
11280 
11281 /** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
11282  *
11283  * All flags can be set via SCIPconsSetFLAGNAME-methods.
11284  *
11285  * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
11286  *
11287  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11288  */
11290  SCIP* scip, /**< SCIP data structure */
11291  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11292  const char* name, /**< name of constraint */
11293  int nlinvars, /**< number of linear terms */
11294  SCIP_VAR** linvars, /**< array with variables in linear part */
11295  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
11296  int nquadterms, /**< number of quadratic terms */
11297  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
11298  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
11299  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
11300  SCIP_Real lhs, /**< left hand side of quadratic equation */
11301  SCIP_Real rhs /**< right hand side of quadratic equation */
11302  )
11303 {
11304  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11305  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11306 
11307  return SCIP_OKAY;
11308 }
11309 
11310 /** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
11311  *
11312  * \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$
11313  *
11314  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11315  */
11317  SCIP* scip, /**< SCIP data structure */
11318  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11319  const char* name, /**< name of constraint */
11320  int nvars, /**< number of variables on left hand side of constraint (n) */
11321  SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
11322  SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
11323  SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
11324  SCIP_Real constant, /**< constant on left hand side (gamma) */
11325  SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
11326  SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
11327  SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
11328  )
11329 {
11330  SCIP_EXPR* expr;
11331  SCIP_EXPR* lhssum;
11332  SCIP_EXPR* terms[2];
11333  SCIP_Real termcoefs[2];
11334  int i;
11335 
11336  assert(vars != NULL || nvars == 0);
11337 
11338  SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
11339  for( i = 0; i < nvars; ++i )
11340  {
11341  SCIP_EXPR* varexpr;
11342  SCIP_EXPR* powexpr;
11343 
11344  SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
11345  if( offsets != NULL && offsets[i] != 0.0 )
11346  {
11347  SCIP_EXPR* sum;
11348  SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
11349  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
11350  SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
11351  }
11352  else
11353  {
11354  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
11355  }
11356 
11357  SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
11358  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
11359  SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
11360  }
11361 
11362  SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
11363  SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
11364  termcoefs[0] = 1.0;
11365 
11366  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
11367  termcoefs[1] = -rhscoeff;
11368 
11369  SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
11370 
11371  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11372  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11373 
11374  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
11375 
11376  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
11377 
11378  return SCIP_OKAY;
11379 }
11380 
11381 /** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
11382  *
11383  * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
11384  *
11385  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11386  */
11388  SCIP* scip, /**< SCIP data structure */
11389  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11390  const char* name, /**< name of constraint */
11391  SCIP_VAR* x, /**< nonlinear variable x in constraint */
11392  SCIP_VAR* z, /**< linear variable z in constraint */
11393  SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
11394  SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
11395  SCIP_Real zcoef, /**< coefficient of z in constraint */
11396  SCIP_Real lhs, /**< left hand side of constraint */
11397  SCIP_Real rhs /**< right hand side of constraint */
11398  )
11399 {
11400  SCIP_EXPR* xexpr;
11401  SCIP_EXPR* terms[2];
11402  SCIP_Real coefs[2];
11403  SCIP_EXPR* sumexpr;
11404 
11405  assert(x != NULL);
11406  assert(z != NULL);
11407 
11408  SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
11409  if( xoffset != 0.0 )
11410  {
11411  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
11412  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
11413 
11414  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11415  }
11416  else
11417  {
11418  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
11419  }
11420  coefs[0] = 1.0;
11421 
11422  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
11423  coefs[1] = zcoef;
11424 
11425  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
11426 
11427  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
11428 
11429  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
11430  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
11431  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
11432  SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
11433 
11434  return SCIP_OKAY;
11435 }
11436 
11437 /** gets tag indicating current local variable bounds */
11439  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11440  )
11441 {
11442  SCIP_CONSHDLRDATA* conshdlrdata;
11443 
11444  assert(conshdlr != NULL);
11445  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11446 
11447  return conshdlrdata->curboundstag;
11448 }
11449 
11450 /** gets the `curboundstag` from the last time where variable bounds were relaxed */
11452  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11453  )
11454 {
11455  SCIP_CONSHDLRDATA* conshdlrdata;
11456 
11457  assert(conshdlr != NULL);
11458  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11459 
11460  return conshdlrdata->lastboundrelax;
11461 }
11462 
11463 /** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
11464  *
11465  * @attention This method is not intended for normal use.
11466  * These tags are maintained by the event handler for variable bound change events.
11467  * This method is used by some unittests.
11468  */
11470  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11471  SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
11472  )
11473 {
11474  SCIP_CONSHDLRDATA* conshdlrdata;
11475 
11476  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11477  assert(conshdlrdata != NULL);
11478 
11479  ++conshdlrdata->curboundstag;
11480  assert(conshdlrdata->curboundstag > 0);
11481 
11482  if( boundrelax )
11483  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
11484 }
11485 
11486 /** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
11488  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11489  )
11490 {
11491  assert(conshdlr != NULL);
11492 
11493  return SCIPconshdlrGetData(conshdlr)->var2expr;
11494 }
11495 
11496 /** processes a rowprep for cut addition and maybe report branchscores */
11498  SCIP* scip, /**< SCIP data structure */
11499  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
11500  SCIP_CONS* cons, /**< nonlinear constraint */
11501  SCIP_EXPR* expr, /**< expression */
11502  SCIP_ROWPREP* rowprep, /**< cut to be added */
11503  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
11504  SCIP_VAR* auxvar, /**< auxiliary variable */
11505  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
11506  SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
11507  SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
11508  SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
11509  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
11510  SCIP_RESULT* result /**< pointer to store the result */
11511  )
11512 {
11513  SCIP_Real cutviol;
11514  SCIP_CONSHDLRDATA* conshdlrdata;
11515  SCIP_Real auxvarvalue = SCIP_INVALID;
11516  SCIP_Bool sepasuccess;
11517  SCIP_Real estimateval = SCIP_INVALID;
11518  SCIP_Real mincutviolation;
11519 
11520  assert(nlhdlr != NULL);
11521  assert(cons != NULL);
11522  assert(expr != NULL);
11523  assert(rowprep != NULL);
11524  assert(auxvar != NULL);
11525  assert(result != NULL);
11526 
11527  /* decide on minimal violation of cut */
11528  if( sol == NULL )
11529  mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
11530  else
11531  mincutviolation = SCIPfeastol(scip);
11532 
11533  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11534  assert(conshdlrdata != NULL);
11535 
11536  sepasuccess = TRUE;
11537 
11538  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
11539  if( cutviol > 0.0 )
11540  {
11541  auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
11542 
11543  /* check whether cut is weak (if f(x) not defined, then it's never weak) */
11544  if( !allowweakcuts && auxvalue != SCIP_INVALID )
11545  {
11546  /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
11547  * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
11548  * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
11549  * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
11550  * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
11551  * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
11552  *
11553  * if we are overestimating, we have z >= c'x-b >= f(x)
11554  * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
11555  * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
11556  * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
11557  *
11558  * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
11559  */
11560  if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11561  ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11562  {
11563  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
11564  "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11565  SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11566  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
11567  sepasuccess = FALSE;
11568  }
11569  }
11570 
11571  /* save estimator value for later, see long comment above why this gives the value for c'x-b */
11572  estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
11573  }
11574  else
11575  {
11576  sepasuccess = FALSE;
11577  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
11578  "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
11579  }
11580 
11581  /* clean up estimator */
11582  if( sepasuccess )
11583  {
11584  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
11585  "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
11586  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
11587  SCIPprintRowprep(scip, rowprep, enfologfile); )
11588 
11589  /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
11590  * instead, may even scale them down, that is, scale so that max coef is close to 1
11591  */
11592  if( !allowweakcuts )
11593  {
11594  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
11595 
11596  if( !sepasuccess )
11597  {
11598  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
11599  }
11600  else
11601  {
11602  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
11603  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
11604  "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
11605  if( sepasuccess )
11606  sepasuccess = cutviol > mincutviolation;
11607  }
11608 
11609  if( sepasuccess && auxvalue != SCIP_INVALID )
11610  {
11611  /* check whether cut is weak now
11612  * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
11613  * reconstructing estimateval from cutviol (TODO improve or remove?)
11614  */
11615  SCIP_Real auxvarcoef = 0.0;
11616  int i;
11617 
11618  /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
11619  * it should be...
11620  */
11621  for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
11622  {
11623  if( SCIProwprepGetVars(rowprep)[i] == auxvar )
11624  {
11625  auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
11626  break;
11627  }
11628  }
11629 
11630  if( auxvarcoef == 0.0 ||
11631  (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
11632  ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
11633  {
11634  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
11635  auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
11636  sepasuccess = FALSE;
11637  }
11638  }
11639  }
11640  else
11641  {
11642  /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
11643 
11644  /* if estimate didn't report branchscores explicitly, then consider branching on those children for
11645  * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
11646  */
11647  if( !branchscoresuccess )
11649 
11650  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
11651 
11652  if( !sepasuccess )
11653  {
11654  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
11655  SCIProwprepGetNModifiedVars(rowprep), cutviol); )
11656  }
11657 
11658  /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
11659  * changed
11660  */
11661  if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
11662  {
11663  SCIP_Real violscore;
11664 
11665 #ifdef BRSCORE_ABSVIOL
11666  violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
11667 #else
11668  SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
11669 #endif
11670  SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
11671 
11672  /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
11673  * - were fixed,
11674  * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
11675  * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
11676  * the first case came up again in #3085 and I don't see how to exclude this in the assert,
11677  * so I'm disabling the assert for now
11678  */
11679  /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
11680  strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
11681  }
11682  }
11683  }
11684 
11685  /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
11686  if( sepasuccess )
11687  {
11688  SCIP_ROW* row;
11689 
11690  if( conshdlrdata->branchdualweight > 0.0 )
11691  {
11692  /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
11693  * skip if gap is zero
11694  */
11695  if( auxvalue == SCIP_INVALID )
11696  strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
11697  else if( !SCIPisEQ(scip, auxvalue, estimateval) )
11698  {
11699  char gap[40];
11700  (void) SCIPsnprintf(gap, 40, "_estimategap=%g", REALABS(auxvalue - estimateval));
11701  strcat(SCIProwprepGetName(rowprep), gap);
11702  }
11703  }
11704 
11705  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
11706 
11707  if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
11708  {
11709  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
11710  SCIPgetCutEfficacy(scip, sol, row), SCIPgetSepaMinEfficacy(scip)); )
11711  }
11712  else if( !SCIPisCutApplicable(scip, row) )
11713  {
11714  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
11715  }
11716  else
11717  {
11718  SCIP_Bool infeasible;
11719 
11720  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
11721  SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
11722 
11723  /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
11724  * if we haven't found strong cuts before)
11725  */
11726  SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
11727 
11728  /* mark row as not removable from LP for current node (this can prevent some cycling) */
11729  if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
11730  SCIPmarkRowNotRemovableLocal(scip, row);
11731 
11732  if( infeasible )
11733  {
11734  *result = SCIP_CUTOFF;
11736  }
11737  else
11738  {
11739  *result = SCIP_SEPARATED;
11741  }
11742  }
11743 
11744  SCIP_CALL( SCIPreleaseRow(scip, &row) );
11745  }
11746  else if( branchscoresuccess )
11747  {
11748  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
11749  "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
11750 
11751  /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
11752  * expressions eligible for branching candidate, see enforceConstraints() and branching()
11753  */
11754  *result = SCIP_BRANCHED;
11755  }
11756  else
11757  {
11758  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
11759  "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
11760  " (!)" : ""); )
11761  }
11762 
11763  return SCIP_OKAY;
11764 }
11765 
11766 /** returns whether all nonlinear constraints are assumed to be convex */
11768  SCIP_CONSHDLR* conshdlr
11769  )
11770 {
11771  SCIP_CONSHDLRDATA* conshdlrdata;
11772 
11773  assert(conshdlr != NULL);
11774 
11775  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11776  assert(conshdlrdata != NULL);
11777 
11778  return conshdlrdata->assumeconvex;
11779 }
11780 
11781 /** collects all bilinear terms for a given set of constraints
11782  *
11783  * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
11784  * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
11785  */
11787  SCIP* scip, /**< SCIP data structure */
11788  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11789  SCIP_CONS** conss, /**< nonlinear constraints */
11790  int nconss /**< total number of nonlinear constraints */
11791  )
11792 {
11793  assert(conshdlr != NULL);
11794  assert(conss != NULL || nconss == 0);
11795 
11796  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11797 
11798  return SCIP_OKAY;
11799 }
11800 
11801 /** returns the total number of bilinear terms that are contained in all nonlinear constraints
11802  *
11803  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11804  */
11806  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11807  )
11808 {
11809  SCIP_CONSHDLRDATA* conshdlrdata;
11810 
11811  assert(conshdlr != NULL);
11812 
11813  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11814  assert(conshdlrdata != NULL);
11815 
11816  return conshdlrdata->nbilinterms;
11817 }
11818 
11819 /** returns all bilinear terms that are contained in all nonlinear constraints
11820  *
11821  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11822  * @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.
11823  */
11825  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
11826  )
11827 {
11828  SCIP_CONSHDLRDATA* conshdlrdata;
11829 
11830  assert(conshdlr != NULL);
11831 
11832  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11833  assert(conshdlrdata != NULL);
11834 
11835  return conshdlrdata->bilinterms;
11836 }
11837 
11838 /** returns the index of the bilinear term representing the product of the two given variables
11839  *
11840  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11841  * @return The method returns -1 if the variables do not appear bilinearly.
11842  */
11844  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11845  SCIP_VAR* x, /**< first variable */
11846  SCIP_VAR* y /**< second variable */
11847  )
11848 {
11849  SCIP_CONSHDLRDATA* conshdlrdata;
11851  int idx;
11852 
11853  assert(conshdlr != NULL);
11854  assert(x != NULL);
11855  assert(y != NULL);
11856 
11857  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11858  assert(conshdlrdata != NULL);
11859 
11860  if( conshdlrdata->bilinhashtable == NULL )
11861  {
11862  return -1;
11863  }
11864 
11865  /* ensure that x.index <= y.index */
11866  if( SCIPvarCompare(x, y) == 1 )
11867  {
11868  SCIPswapPointers((void**)&x, (void**)&y);
11869  }
11870  assert(SCIPvarCompare(x, y) < 1);
11871 
11872  /* use a new entry to find the image in the bilinear hash table */
11873  entry.x = x;
11874  entry.y = y;
11875  idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
11876  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11877  assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
11878  assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
11879 
11880  return idx;
11881 }
11882 
11883 /** returns the bilinear term that represents the product of two given variables
11884  *
11885  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
11886  * @return The method returns NULL if the variables do not appear bilinearly.
11887  */
11889  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
11890  SCIP_VAR* x, /**< first variable */
11891  SCIP_VAR* y /**< second variable */
11892  )
11893 {
11894  SCIP_CONSHDLRDATA* conshdlrdata;
11895  int idx;
11896 
11897  assert(conshdlr != NULL);
11898  assert(x != NULL);
11899  assert(y != NULL);
11900 
11901  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11902  assert(conshdlrdata != NULL);
11903 
11904  idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
11905  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
11906 
11907  if( idx >= 0 )
11908  {
11909  return &conshdlrdata->bilinterms[idx];
11910  }
11911 
11912  return NULL;
11913 }
11914 
11915 /** evaluates an auxiliary expression for a bilinear term */
11917  SCIP* scip, /**< SCIP data structure */
11918  SCIP_VAR* x, /**< first variable of the bilinear term */
11919  SCIP_VAR* y, /**< second variable of the bilinear term */
11920  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
11921  SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
11922  )
11923 {
11924  assert(scip != NULL);
11925  assert(x != NULL);
11926  assert(y != NULL);
11927  assert(auxexpr != NULL);
11928  assert(auxexpr->auxvar != NULL);
11929 
11930  return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
11931  auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
11932 }
11933 
11934 /** stores the variables of a bilinear term in the data of the constraint handler */
11936  SCIP* scip, /**< SCIP data structure */
11937  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11938  SCIP_VAR* x, /**< first variable */
11939  SCIP_VAR* y, /**< second variable */
11940  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11941  int nlockspos, /**< number of positive expression locks */
11942  int nlocksneg /**< number of negative expression locks */
11943  )
11944 {
11945  SCIP_CONSHDLRDATA* conshdlrdata;
11947  int idx;
11948 
11949  assert(conshdlr != NULL);
11950 
11951  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11952  assert(conshdlrdata != NULL);
11953 
11954  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
11955 
11956  term = &conshdlrdata->bilinterms[idx];
11957  assert(term != NULL);
11958  assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
11959  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) */
11960 
11961  /* store and capture auxiliary variable */
11962  if( auxvar != NULL )
11963  {
11964  term->aux.var = auxvar;
11965  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
11966  }
11967 
11968  return SCIP_OKAY;
11969 }
11970 
11971 /** stores the variables of a bilinear term in the data of the constraint handler */
11973  SCIP* scip, /**< SCIP data structure */
11974  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11975  SCIP_VAR* x, /**< first variable */
11976  SCIP_VAR* y, /**< second variable */
11977  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
11978  SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
11979  SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
11980  SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
11981  SCIP_Real cst, /**< constant of the auxiliary expression */
11982  SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
11983  )
11984 {
11985  SCIP_CONSHDLRDATA* conshdlrdata;
11987  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr;
11988  int idx;
11989  int nlockspos;
11990  int nlocksneg;
11991  SCIP_Bool added;
11992 
11993  assert(conshdlr != NULL);
11994 
11995  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11996  assert(conshdlrdata != NULL);
11997 
11998  nlockspos = overestimate ? 1 : 0;
11999  nlocksneg = overestimate ? 0 : 1;
12000 
12001  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
12002 
12003  term = &conshdlrdata->bilinterms[idx];
12004  assert(term != NULL);
12005  assert(SCIPvarCompare(term->x, term->y) < 1);
12006 
12007  if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
12008  {
12009  SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
12010  /* this is the case where we are adding an implicitly defined relation for a product that has already
12011  * been explicitly defined; convert auxvar into an auxexpr */
12012 
12013  /* nothing to do if we aren't allowed to add more than one auxexpr per term */
12014  if( conshdlrdata->bilinmaxnauxexprs <= 1 )
12015  return SCIP_OKAY;
12016 
12017  SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
12018  auxvarexpr->cst = 0.0;
12019  auxvarexpr->coefs[0] = 1.0;
12020  auxvarexpr->coefs[1] = 0.0;
12021  auxvarexpr->coefs[2] = 0.0;
12022  auxvarexpr->auxvar = term->aux.var;
12023  auxvarexpr->underestimate = term->nlocksneg > 0;
12024  auxvarexpr->overestimate = term->nlockspos > 0;
12025 
12026  /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
12027  term->aux.exprs = NULL;
12028 
12029  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
12030 
12031  /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
12032  assert(added);
12033  }
12034 
12035  /* create and add auxexpr */
12036  SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
12037  auxexpr->underestimate = !overestimate;
12038  auxexpr->overestimate = overestimate;
12039  auxexpr->auxvar = auxvar;
12040  auxexpr->coefs[0] = coefaux;
12041  if( term->x == x )
12042  {
12043  assert(term->y == y);
12044  auxexpr->coefs[1] = coefx;
12045  auxexpr->coefs[2] = coefy;
12046  }
12047  else
12048  {
12049  assert(term->x == y);
12050  assert(term->y == x);
12051  auxexpr->coefs[1] = coefy;
12052  auxexpr->coefs[2] = coefx;
12053  }
12054  auxexpr->cst = cst;
12055  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
12056 
12057  if( !added )
12058  {
12059  SCIPfreeBlockMemory(scip, &auxexpr);
12060  }
12061  else if( auxvar != NULL )
12062  { /* capture auxiliary variable */
12063  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
12064  }
12065 
12066  return SCIP_OKAY;
12067 }
12068 
12069 /* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
12071  SCIP* scip, /**< SCIP data structure */
12072  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12073  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
12074  SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
12075  void* fundata, /**< data for function evaluation (can be NULL) */
12076  SCIP_Real* xstar, /**< point to be separated */
12077  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
12078  int nallvars, /**< half of the length of box */
12079  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
12080  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
12081  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
12082  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
12083  )
12084 {
12085  SCIP_Real* corner;
12086  SCIP_Real* funvals;
12087  int* nonfixedpos;
12088  SCIP_Real maxfaceterror;
12089  int nvars; /* number of nonfixed variables */
12090  unsigned int ncorners;
12091  unsigned int i;
12092  int j;
12093 
12094  assert(scip != NULL);
12095  assert(conshdlr != NULL);
12096  assert(function != NULL);
12097  assert(xstar != NULL);
12098  assert(box != NULL);
12099  assert(success != NULL);
12100  assert(facetcoefs != NULL);
12101  assert(facetconstant != NULL);
12102 
12103  *success = FALSE;
12104 
12105  /* identify fixed variables */
12106  SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
12107  nvars = 0;
12108  for( j = 0; j < nallvars; ++j )
12109  {
12110  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12111  continue;
12112  nonfixedpos[nvars] = j;
12113  nvars++;
12114  }
12115 
12116  /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
12117  * if too many variables are not fixed, then we do nothing currently
12118  */
12119  if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
12120  {
12121  SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
12122  SCIPfreeBufferArray(scip, &nonfixedpos);
12123  return SCIP_OKAY;
12124  }
12125 
12126  /* compute f(v^i) for each corner v^i of [l,u] */
12127  ncorners = POWEROFTWO(nvars);
12128  SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
12129  SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
12130  for( j = 0; j < nallvars; ++j )
12131  {
12132  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
12133  corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
12134  }
12135  for( i = 0; i < ncorners; ++i )
12136  {
12137  SCIPdebugMsg(scip, "corner %u: ", i);
12138  for( j = 0; j < nvars; ++j )
12139  {
12140  int varpos = nonfixedpos[j];
12141  /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
12142  * we check this by shifting i for j positions to the right and checking whether the last bit is set
12143  */
12144  if( (i >> j) & 0x1 )
12145  corner[varpos] = box[2 * varpos + 1]; /* ub of var */
12146  else
12147  corner[varpos] = box[2 * varpos ]; /* lb of var */
12148  SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
12149  assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
12150  }
12151 
12152  funvals[i] = function(corner, nallvars, fundata);
12153 
12154  SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
12155 
12156  if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
12157  {
12158  SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
12159  goto CLEANUP;
12160  }
12161  }
12162 
12163  /* clear coefs array; below we only fill in coefs for nonfixed variables */
12164  BMSclearMemoryArray(facetcoefs, nallvars);
12165 
12166  if( nvars == 1 )
12167  {
12168  SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
12169 
12170  /* check whether target has been missed */
12171  if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
12172  {
12173  SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
12174  *success = FALSE;
12175  }
12176  }
12177  else if( nvars == 2 )
12178  {
12179  int idx1 = nonfixedpos[0];
12180  int idx2 = nonfixedpos[1];
12181  SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
12182  SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
12183  SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
12184  SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
12185  SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
12186  SCIP_Real coefs[2] = { 0.0, 0.0 };
12187 
12188  SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
12189 
12190  facetcoefs[idx1] = coefs[0];
12191  facetcoefs[idx2] = coefs[1];
12192  }
12193  else
12194  {
12195  SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
12196  }
12197  if( !*success )
12198  {
12199  SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
12200  goto CLEANUP;
12201  }
12202 
12203  /*
12204  * check and adjust facet with the algorithm of Rikun et al.
12205  */
12206 
12207  maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
12208 
12209  /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
12210  if( maxfaceterror > 0.0 )
12211  {
12212  SCIP_CONSHDLRDATA* conshdlrdata;
12213  SCIP_Real midval;
12214  SCIP_Real feastol;
12215 
12216  feastol = SCIPgetStage(scip) == SCIP_STAGE_SOLVING ? SCIPgetLPFeastol(scip) : SCIPfeastol(scip);
12217 
12218  /* evaluate function in middle point to get some idea for a scaling */
12219  for( j = 0; j < nvars; ++j )
12220  corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
12221  midval = function(corner, nallvars, fundata);
12222  if( midval == SCIP_INVALID )
12223  midval = 1.0;
12224 
12225  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12226  assert(conshdlrdata != NULL);
12227 
12228  /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
12229  if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
12230  {
12231  SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
12232  *success = FALSE;
12233  goto CLEANUP;
12234  }
12235 
12236  SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
12237 
12238  if( overestimate )
12239  *facetconstant += maxfaceterror;
12240  else
12241  *facetconstant -= maxfaceterror;
12242  }
12243 
12244  /* if we made it until here, then we have a nice facet */
12245  assert(*success);
12246 
12247 CLEANUP:
12248  /* free allocated memory */
12249  SCIPfreeBufferArray(scip, &corner);
12250  SCIPfreeBufferArray(scip, &funvals);
12251  SCIPfreeBufferArray(scip, &nonfixedpos);
12252 
12253  return SCIP_OKAY;
12254 }
12255 
12256 /*
12257  * constraint specific interface methods
12258  */
12259 
12260 /** returns the expression of the given nonlinear constraint */
12262  SCIP_CONS* cons /**< constraint data */
12263  )
12264 {
12265  SCIP_CONSDATA* consdata;
12266 
12267  assert(cons != NULL);
12268  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12269 
12270  consdata = SCIPconsGetData(cons);
12271  assert(consdata != NULL);
12272 
12273  return consdata->expr;
12274 }
12275 
12276 /** gets the left hand side of a nonlinear constraint */
12278  SCIP_CONS* cons /**< constraint data */
12279  )
12280 {
12281  SCIP_CONSDATA* consdata;
12282 
12283  assert(cons != NULL);
12284  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12285 
12286  consdata = SCIPconsGetData(cons);
12287  assert(consdata != NULL);
12288 
12289  return consdata->lhs;
12290 }
12291 
12292 /** gets the right hand side of a nonlinear constraint */
12294  SCIP_CONS* cons /**< constraint data */
12295  )
12296 {
12297  SCIP_CONSDATA* consdata;
12298 
12299  assert(cons != NULL);
12300  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12301 
12302  consdata = SCIPconsGetData(cons);
12303  assert(consdata != NULL);
12304 
12305  return consdata->rhs;
12306 }
12307 
12308 /** gets the nonlinear constraint as a nonlinear row representation. */
12310  SCIP* scip, /**< SCIP data structure */
12311  SCIP_CONS* cons, /**< constraint */
12312  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
12313  )
12314 {
12315  SCIP_CONSDATA* consdata;
12316 
12317  assert(cons != NULL);
12318  assert(nlrow != NULL);
12319  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12320 
12321  consdata = SCIPconsGetData(cons);
12322  assert(consdata != NULL);
12323 
12324  if( consdata->nlrow == NULL )
12325  {
12326  SCIP_CALL( createNlRow(scip, cons) );
12327  }
12328  assert(consdata->nlrow != NULL);
12329  *nlrow = consdata->nlrow;
12330 
12331  return SCIP_OKAY;
12332 }
12333 
12334 /** returns the curvature of the expression of a given nonlinear constraint
12335  *
12336  * @note The curvature information is computed during CONSINITSOL.
12337  */
12339  SCIP_CONS* cons /**< constraint data */
12340  )
12341 {
12342  SCIP_CONSDATA* consdata;
12343 
12344  assert(cons != NULL);
12345  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12346 
12347  consdata = SCIPconsGetData(cons);
12348  assert(consdata != NULL);
12349 
12350  return consdata->curv;
12351 }
12352 
12353 /** checks whether expression of constraint can be represented as quadratic form
12354  *
12355  * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
12356  * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
12357  * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
12358  */
12360  SCIP* scip, /**< SCIP data structure */
12361  SCIP_CONS* cons, /**< constraint data */
12362  SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
12363  )
12364 {
12365  SCIP_CONSDATA* consdata;
12366 
12367  assert(scip != NULL);
12368  assert(cons != NULL);
12369  assert(isquadratic != NULL);
12370  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12371 
12372  consdata = SCIPconsGetData(cons);
12373  assert(consdata != NULL);
12374  assert(consdata->expr != NULL);
12375 
12376  /* check whether constraint expression is quadratic in extended formulation */
12377  SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
12378 
12379  /* if not quadratic in non-extended formulation, then do indicate quadratic */
12380  if( *isquadratic )
12381  *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
12382 
12383  return SCIP_OKAY;
12384 }
12385 
12386 /** changes left-hand-side of a nonlinear constraint
12387  *
12388  * @attention This method can only be called in the problem stage.
12389  */
12391  SCIP* scip, /**< SCIP data structure */
12392  SCIP_CONS* cons, /**< constraint data */
12393  SCIP_Real lhs /**< new left-hand-side */
12394  )
12395 {
12396  SCIP_CONSDATA* consdata;
12397 
12398  assert(scip != NULL);
12399  assert(cons != NULL);
12400  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12401 
12402  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12403  {
12404  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12405  return SCIP_INVALIDCALL;
12406  }
12407 
12408  /* we should have an original constraint */
12409  assert(SCIPconsIsOriginal(cons));
12410 
12411  consdata = SCIPconsGetData(cons);
12412  assert(consdata != NULL);
12413 
12414  if( consdata->lhs == lhs )
12415  return SCIP_OKAY;
12416 
12417  consdata->lhs = lhs;
12418 
12419  /* not sure we care about any of these flags for original constraints */
12420  consdata->ispropagated = FALSE;
12421 
12422  return SCIP_OKAY;
12423 }
12424 
12425 /** changes right-hand-side of a nonlinear constraint
12426  *
12427  * @attention This method can only be called in the problem stage.
12428  */
12430  SCIP* scip, /**< SCIP data structure */
12431  SCIP_CONS* cons, /**< constraint data */
12432  SCIP_Real rhs /**< new right-hand-side */
12433  )
12434 {
12435  SCIP_CONSDATA* consdata;
12436 
12437  assert(scip != NULL);
12438  assert(cons != NULL);
12439  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
12440 
12441  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12442  {
12443  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
12444  return SCIP_INVALIDCALL;
12445  }
12446 
12447  /* we should have an original constraint */
12448  assert(SCIPconsIsOriginal(cons));
12449 
12450  consdata = SCIPconsGetData(cons);
12451  assert(consdata != NULL);
12452 
12453  if( consdata->rhs == rhs )
12454  return SCIP_OKAY;
12455 
12456  consdata->rhs = rhs;
12457 
12458  /* not sure we care about any of these flags for original constraints */
12459  consdata->ispropagated = FALSE;
12460 
12461  return SCIP_OKAY;
12462 }
12463 
12464 /** changes expression of a nonlinear constraint
12465  *
12466  * @attention This method can only be called in the problem stage.
12467  */
12469  SCIP* scip, /**< SCIP data structure */
12470  SCIP_CONS* cons, /**< constraint data */
12471  SCIP_EXPR* expr /**< new expression */
12472  )
12473 {
12474  SCIP_CONSHDLR* conshdlr;
12475  SCIP_CONSDATA* consdata;
12476 
12477  assert(scip != NULL);
12478  assert(cons != NULL);
12479  assert(expr != NULL);
12480 
12481  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12482  {
12483  SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
12484  return SCIP_INVALIDCALL;
12485  }
12486 
12487  /* we should have an original constraint */
12488  assert(SCIPconsIsOriginal(cons));
12489 
12490  conshdlr = SCIPconsGetHdlr(cons);
12491  assert(conshdlr != NULL);
12492  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12493 
12494  consdata = SCIPconsGetData(cons);
12495  assert(consdata != NULL);
12496  assert(consdata->expr != NULL);
12497 
12498  /* we should not have collected additional data for the expr
12499  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12500  */
12501  assert(consdata->nvarexprs == 0);
12502  assert(consdata->varexprs == NULL);
12503  assert(!consdata->catchedevents);
12504 
12505  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
12506 
12507  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12508  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12509 
12510  /* not sure we care about any of these flags for original constraints */
12511  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
12512  consdata->issimplified = FALSE;
12513  consdata->ispropagated = FALSE;
12514 
12515  return SCIP_OKAY;
12516 }
12517 
12518 /** adds coef * var to nonlinear constraint
12519  *
12520  * @attention This method can only be called in the problem stage.
12521  */
12523  SCIP* scip, /**< SCIP data structure */
12524  SCIP_CONS* cons, /**< constraint data */
12525  SCIP_VAR* var, /**< variable */
12526  SCIP_Real coef /**< coefficient */
12527  )
12528 {
12529  SCIP_CONSHDLR* conshdlr;
12530  SCIP_CONSDATA* consdata;
12531  SCIP_EXPR* varexpr;
12532 
12533  assert(scip != NULL);
12534  assert(cons != NULL);
12535 
12536  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12537  {
12538  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12539  return SCIP_INVALIDCALL;
12540  }
12541 
12542  /* we should have an original constraint */
12543  assert(SCIPconsIsOriginal(cons));
12544 
12545  if( coef == 0.0 )
12546  return SCIP_OKAY;
12547 
12548  conshdlr = SCIPconsGetHdlr(cons);
12549  assert(conshdlr != NULL);
12550  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12551 
12552  consdata = SCIPconsGetData(cons);
12553  assert(consdata != NULL);
12554  assert(consdata->expr != NULL);
12555 
12556  /* we should not have collected additional data for it
12557  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12558  */
12559  assert(consdata->nvarexprs == 0);
12560  assert(consdata->varexprs == NULL);
12561  assert(!consdata->catchedevents);
12562 
12563  SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
12564 
12565  /* append to sum, if consdata->expr is sum and not used anywhere else */
12566  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12567  {
12568  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
12569  }
12570  else
12571  {
12572  /* create new expression = 1 * consdata->expr + coef * var */
12573  SCIP_EXPR* children[2] = { consdata->expr, varexpr };
12574  SCIP_Real coefs[2] = { 1.0, coef };
12575 
12576  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12577 
12578  /* release old root expr */
12579  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12580  }
12581 
12582  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12583 
12584  /* not sure we care about any of these flags for original constraints */
12585  consdata->issimplified = FALSE;
12586  consdata->ispropagated = FALSE;
12587 
12588  return SCIP_OKAY;
12589 }
12590 
12591 /** adds coef * expr to nonlinear constraint
12592  *
12593  * @attention This method can only be called in the problem stage.
12594  */
12596  SCIP* scip, /**< SCIP data structure */
12597  SCIP_CONS* cons, /**< nonlinear constraint */
12598  SCIP_EXPR* expr, /**< expression */
12599  SCIP_Real coef /**< coefficient */
12600  )
12601 {
12602  SCIP_CONSHDLR* conshdlr;
12603  SCIP_CONSDATA* consdata;
12604  SCIP_EXPR* exprowned;
12605 
12606  assert(scip != NULL);
12607  assert(cons != NULL);
12608 
12609  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
12610  {
12611  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
12612  return SCIP_INVALIDCALL;
12613  }
12614 
12615  /* we should have an original constraint */
12616  assert(SCIPconsIsOriginal(cons));
12617 
12618  if( coef == 0.0 )
12619  return SCIP_OKAY;
12620 
12621  conshdlr = SCIPconsGetHdlr(cons);
12622  assert(conshdlr != NULL);
12623  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12624 
12625  consdata = SCIPconsGetData(cons);
12626  assert(consdata != NULL);
12627  assert(consdata->expr != NULL);
12628 
12629  /* we should not have collected additional data for it
12630  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
12631  */
12632  assert(consdata->nvarexprs == 0);
12633  assert(consdata->varexprs == NULL);
12634  assert(!consdata->catchedevents);
12635 
12636  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
12637  SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
12638 
12639  /* append to sum, if consdata->expr is sum and not used anywhere else */
12640  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
12641  {
12642  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
12643  }
12644  else
12645  {
12646  /* create new expression = 1 * consdata->expr + coef * var */
12647  SCIP_EXPR* children[2] = { consdata->expr, exprowned };
12648  SCIP_Real coefs[2] = { 1.0, coef };
12649 
12650  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
12651 
12652  /* release old root expr */
12653  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
12654  }
12655 
12656  SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
12657 
12658  /* not sure we care about any of these flags for original constraints */
12659  consdata->issimplified = FALSE;
12660  consdata->ispropagated = FALSE;
12661 
12662  return SCIP_OKAY;
12663 }
12664 
12665 /** gets absolute violation of nonlinear constraint
12666  *
12667  * This function evaluates the constraints in the given solution.
12668  *
12669  * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
12670  */
12672  SCIP* scip, /**< SCIP data structure */
12673  SCIP_CONS* cons, /**< constraint */
12674  SCIP_SOL* sol, /**< solution to check */
12675  SCIP_Real* viol /**< buffer to store computed violation */
12676  )
12677 {
12678  assert(cons != NULL);
12679  assert(viol != NULL);
12680 
12681  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12682  *viol = getConsAbsViolation(cons);
12683 
12684  return SCIP_OKAY;
12685 }
12686 
12687 /** gets scaled violation of nonlinear constraint
12688  *
12689  * This function evaluates the constraints in the given solution.
12690  *
12691  * The scaling that is applied to the absolute violation of the constraint
12692  * depends on the setting of parameter constraints/nonlinear/violscale.
12693  */
12695  SCIP* scip, /**< SCIP data structure */
12696  SCIP_CONS* cons, /**< constraint */
12697  SCIP_SOL* sol, /**< solution to check */
12698  SCIP_Real* viol /**< buffer to store computed violation */
12699  )
12700 {
12701  assert(cons != NULL);
12702  assert(viol != NULL);
12703 
12704  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
12705  SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
12706 
12707  return SCIP_OKAY;
12708 }
12709 
12710 /** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
12712  SCIP* scip, /**< SCIP data structure */
12713  SCIP_CONS* cons, /**< nonlinear constraint */
12714  SCIP_VAR** var, /**< pointer to store the variable */
12715  SCIP_Real* coef /**< pointer to store the coefficient */
12716  )
12717 {
12718  SCIP_CONSDATA* consdata;
12719 
12720  assert(cons != NULL);
12721  assert(var != NULL);
12722  assert(coef != NULL);
12723 
12724  /* check for a linear variable that can be increased or decreased without harming feasibility */
12725  findUnlockedLinearVar(scip, cons);
12726 
12727  consdata = SCIPconsGetData(cons);
12728  assert(consdata != NULL);
12729 
12730  *var = consdata->linvardecr;
12731  *coef = consdata->linvardecrcoef;
12732 }
12733 
12734 /** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
12736  SCIP* scip, /**< SCIP data structure */
12737  SCIP_CONS* cons, /**< nonlinear constraint */
12738  SCIP_VAR** var, /**< pointer to store the variable */
12739  SCIP_Real* coef /**< pointer to store the coefficient */
12740  )
12741 {
12742  SCIP_CONSDATA* consdata;
12743 
12744  assert(cons != NULL);
12745  assert(var != NULL);
12746  assert(coef != NULL);
12747 
12748  /* check for a linear variable that can be increased or decreased without harming feasibility */
12749  findUnlockedLinearVar(scip, cons);
12750 
12751  consdata = SCIPconsGetData(cons);
12752  assert(consdata != NULL);
12753 
12754  *var = consdata->linvarincr;
12755  *coef = consdata->linvarincrcoef;
12756 }
12757 
12758 
12759 /*
12760  * Methods for Expressions in Nonlinear Constraints
12761  */
12762 
12763 /** returns the number of positive rounding locks of an expression */
12765  SCIP_EXPR* expr /**< expression */
12766  )
12767 {
12768  assert(expr != NULL);
12769  assert(SCIPexprGetOwnerData(expr) != NULL);
12770 
12771  return SCIPexprGetOwnerData(expr)->nlockspos;
12772 }
12773 
12774 /** returns the number of negative rounding locks of an expression */
12776  SCIP_EXPR* expr /**< expression */
12777  )
12778 {
12779  assert(expr != NULL);
12780  assert(SCIPexprGetOwnerData(expr) != NULL);
12781 
12782  return SCIPexprGetOwnerData(expr)->nlocksneg;
12783 }
12784 
12785 /** returns the variable used for linearizing a given expression (return value might be NULL)
12786  *
12787  * @note for variable expression it returns the corresponding variable
12788  */
12790  SCIP_EXPR* expr /**< expression */
12791  )
12792 {
12793  SCIP_EXPR_OWNERDATA* ownerdata;
12794 
12795  assert(expr != NULL);
12796 
12797  ownerdata = SCIPexprGetOwnerData(expr);
12798  assert(ownerdata != NULL);
12799 
12800  return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
12801 }
12802 
12803 /** returns the number of enforcements for an expression */
12805  SCIP_EXPR* expr /**< expression */
12806  )
12807 {
12808  assert(expr != NULL);
12809  assert(SCIPexprGetOwnerData(expr) != NULL);
12810 
12811  return SCIPexprGetOwnerData(expr)->nenfos;
12812 }
12813 
12814 /** returns the data for one of the enforcements of an expression */
12816  SCIP_EXPR* expr, /**< expression */
12817  int idx, /**< position of enforcement in enfos array */
12818  SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
12819  SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
12820  SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
12821  SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
12822  SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
12823  SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
12824  )
12825 {
12826  SCIP_EXPR_OWNERDATA* ownerdata;
12827 
12828  assert(expr != NULL);
12829 
12830  ownerdata = SCIPexprGetOwnerData(expr);
12831  assert(ownerdata != NULL);
12832  assert(idx >= 0);
12833  assert(idx < ownerdata->nenfos);
12834  assert(ownerdata->enfos[idx] != NULL);
12835  assert(nlhdlr != NULL);
12836 
12837  *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
12838 
12839  if( nlhdlrexprdata != NULL )
12840  *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
12841 
12842  if( nlhdlrparticipation != NULL )
12843  *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
12844 
12845  if( sepabelowusesactivity != NULL )
12846  *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
12847 
12848  if( sepaaboveusesactivity != NULL )
12849  *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
12850 
12851  if( auxvalue != NULL )
12852  *auxvalue = ownerdata->enfos[idx]->auxvalue;
12853 }
12854 
12855 /** sets the auxiliary value of expression for one of the enforcements of an expression */
12857  SCIP_EXPR* expr, /**< expression */
12858  int idx, /**< position of enforcement in enfos array */
12859  SCIP_Real auxvalue /**< the new value of auxval */
12860  )
12861 {
12862  SCIP_EXPR_OWNERDATA* ownerdata;
12863 
12864  assert(expr != NULL);
12865 
12866  ownerdata = SCIPexprGetOwnerData(expr);
12867  assert(ownerdata != NULL);
12868 
12869  assert(idx >= 0);
12870  assert(idx < ownerdata->nenfos);
12871  assert(ownerdata->enfos[idx] != NULL);
12872 
12873  ownerdata->enfos[idx]->auxvalue = auxvalue;
12874 }
12875 
12876 /** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
12877  *
12878  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12879  */
12881  SCIP_EXPR* expr /**< expression */
12882  )
12883 {
12884  assert(expr != NULL);
12885  assert(SCIPexprGetOwnerData(expr) != NULL);
12886 
12887  return SCIPexprGetOwnerData(expr)->nactivityusesprop;
12888 }
12889 
12890 /** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
12891  *
12892  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12893  */
12895  SCIP_EXPR* expr /**< expression */
12896  )
12897 {
12898  assert(expr != NULL);
12899  assert(SCIPexprGetOwnerData(expr) != NULL);
12900 
12901  return SCIPexprGetOwnerData(expr)->nactivityusessepa;
12902 }
12903 
12904 /** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
12905  *
12906  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
12907  */
12908 unsigned int SCIPgetExprNAuxvarUsesNonlinear(
12909  SCIP_EXPR* expr /**< expression */
12910  )
12911 {
12912  assert(expr != NULL);
12913  assert(SCIPexprGetOwnerData(expr) != NULL);
12914 
12915  return SCIPexprGetOwnerData(expr)->nauxvaruses;
12916 }
12917 
12918 /** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
12919  *
12920  * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
12921  * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
12922  * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
12923  * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
12924  * and also increments this count for all variables in the expression.
12925  *
12926  * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
12927  * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
12928  * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
12929  * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
12930  */
12932  SCIP* scip, /**< SCIP data structure */
12933  SCIP_EXPR* expr, /**< expression */
12934  SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
12935  SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
12936  SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
12937  SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
12938  )
12939 {
12940  SCIP_EXPR_OWNERDATA* ownerdata;
12941 
12942  assert(expr != NULL);
12943 
12944  ownerdata = SCIPexprGetOwnerData(expr);
12945  assert(ownerdata != NULL);
12946 
12947  /* do not store auxvar request for variable expressions */
12948  if( useauxvar && SCIPisExprVar(scip, expr) )
12949  useauxvar = FALSE;
12950 
12951  if( ownerdata->nenfos >= 0 &&
12952  ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
12953  (ownerdata->nauxvaruses == 0 && useauxvar)
12954  ) )
12955  {
12956  /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
12957  * we require additional enforcement methods, that is,
12958  * - activity of expr was not used before but will be used now, or
12959  * - auxiliary variable of expr was not required before but will be used now
12960  */
12961  SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
12962  }
12963 
12964  if( useauxvar )
12965  ++ownerdata->nauxvaruses;
12966 
12967  if( useactivityforprop )
12968  ++ownerdata->nactivityusesprop;
12969 
12970  if( useactivityforsepabelow || useactivityforsepaabove )
12971  ++ownerdata->nactivityusessepa;
12972 
12973  /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
12974  * information is used in detectNlhdlr()
12975  */
12976  if( useactivityforsepabelow )
12977  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
12978  if( useactivityforsepaabove )
12979  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
12980 
12981  if( useactivityforprop )
12982  {
12983  /* if activity will be used for propagation, then make sure there is a valid activity
12984  * this way, we can do a reversepropcall after detectNlhdlr
12985  */
12986  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
12987  }
12988 
12989  /* increase the nactivityusedsepa counter for all variables used in the given expression */
12990  if(( useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
12991  {
12992  SCIP_EXPRITER* it;
12993 
12994  /* create and initialize iterator */
12995  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
12997 
12998  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
12999  if( SCIPisExprVar(scip, expr) )
13000  ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
13001 
13002  /* free iterator */
13003  SCIPfreeExpriter(&it);
13004  }
13005 
13006  return SCIP_OKAY;
13007 }
13008 
13009 /** computes absolute violation for auxvar relation in an expression w.r.t. original variables
13010  *
13011  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
13012  * Assume that f(x) is associated with auxiliary variable z.
13013  *
13014  * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
13015  * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
13016  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
13017  *
13018  * If necessary, f is evaluated in the given solution. If that fails (domain error),
13019  * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
13020  */
13022  SCIP* scip, /**< SCIP data structure */
13023  SCIP_EXPR* expr, /**< expression */
13024  SCIP_SOL* sol, /**< solution */
13025  SCIP_Longint soltag, /**< tag of solution */
13026  SCIP_Real* viol, /**< buffer to store computed violation */
13027  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
13028  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
13029  )
13030 {
13031  assert(scip != NULL);
13032  assert(expr != NULL);
13033  assert(viol != NULL);
13034 
13035  /* make sure expression has been evaluated */
13036  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
13037 
13038  /* get violation from internal method */
13039  *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
13040 
13041  return SCIP_OKAY;
13042 }
13043 
13044 /** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
13045  *
13046  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13047  * Assume that f(w) is associated with auxiliary variable z.
13048  *
13049  * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
13050  * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
13051  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
13052  *
13053  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13054  * both `violover` and `violunder` are set to TRUE.
13055  */
13057  SCIP* scip, /**< SCIP data structure */
13058  SCIP_EXPR* expr, /**< expression */
13059  SCIP_Real auxvalue, /**< the value of f(w) */
13060  SCIP_SOL* sol, /**< solution that has been evaluated */
13061  SCIP_Real* viol, /**< buffer to store computed violation */
13062  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13063  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13064  )
13065 {
13066  assert(scip != NULL);
13067  assert(expr != NULL);
13068  assert(viol != NULL);
13069 
13070  /* get violation from internal method */
13071  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13072 
13073  return SCIP_OKAY;
13074 }
13075 
13076 
13077 /** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
13078  *
13079  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
13080  * Assume that f(w) is associated with auxiliary variable z.
13081  *
13082  * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
13083  * the absolute violation divided by max(1,|f(w)|).
13084  *
13085  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
13086  * both `violover` and `violunder` are set to TRUE.
13087  */
13089  SCIP* scip, /**< SCIP data structure */
13090  SCIP_EXPR* expr, /**< expression */
13091  SCIP_Real auxvalue, /**< the value of f(w) */
13092  SCIP_SOL* sol, /**< solution that has been evaluated */
13093  SCIP_Real* viol, /**< buffer to store computed violation */
13094  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
13095  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
13096  )
13097 {
13098  assert(scip != NULL);
13099  assert(expr != NULL);
13100  assert(viol != NULL);
13101 
13102  /* get violation from internal method */
13103  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
13104 
13105  if( !SCIPisInfinity(scip, *viol) )
13106  {
13107  assert(auxvalue != SCIP_INVALID);
13108  /* TODO maybe we should rather use max(eps,|auxvalue|)? */
13109  *viol /= MAX(1.0, REALABS(auxvalue));
13110  }
13111 
13112  return SCIP_OKAY;
13113 }
13114 
13115 /** returns bounds on the expression
13116  *
13117  * This gives an intersection of bounds from
13118  * - activity calculation (SCIPexprGetActivity()), if valid,
13119  * - auxiliary variable, if present,
13120  * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
13121  *
13122  * @note The returned interval can be empty!
13123  */
13125  SCIP* scip, /**< SCIP data structure */
13126  SCIP_EXPR* expr /**< expression */
13127  )
13128 {
13129  SCIP_EXPR_OWNERDATA* ownerdata;
13130  SCIP_CONSHDLRDATA* conshdlrdata;
13131  SCIP_INTERVAL bounds;
13132 
13133  assert(scip != NULL);
13134  assert(expr != NULL);
13135 
13136  ownerdata = SCIPexprGetOwnerData(expr);
13137  assert(ownerdata != NULL);
13138 
13139  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13140  assert(conshdlrdata != NULL);
13141 
13142  /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
13143 
13144  /* start with propbounds if they belong to current propagation */
13145  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13146  {
13147  bounds = ownerdata->propbounds;
13148  /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
13149  }
13150  else
13152 
13153  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
13154  {
13155  /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
13156  /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
13157  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), bounds);
13158  }
13159 
13160  if( ownerdata->auxvar != NULL )
13161  {
13162  /* apply auxiliary variable bounds to bounds */
13163  SCIP_INTERVAL auxvarbounds;
13164 
13165  auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
13166  /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
13167  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
13168  }
13169 
13170  /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
13171 
13172  return bounds;
13173 }
13174 
13175 /** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
13176  * corresponding (auxiliary) variable (if any)
13177  *
13178  * @attention this function should only be called during domain propagation in cons_nonlinear
13179  */
13181  SCIP* scip, /**< SCIP data structure */
13182  SCIP_EXPR* expr, /**< expression to be tightened */
13183  SCIP_INTERVAL newbounds, /**< new bounds for the expression */
13184  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
13185  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
13186  )
13187 {
13188  SCIP_EXPR_OWNERDATA* ownerdata;
13189  SCIP_CONSHDLRDATA* conshdlrdata;
13190 
13191  assert(scip != NULL);
13192  assert(expr != NULL);
13193  assert(cutoff != NULL);
13194 
13195  ownerdata = SCIPexprGetOwnerData(expr);
13196  assert(ownerdata != NULL);
13197  assert(ownerdata->conshdlr != NULL);
13198 
13199  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13200  assert(conshdlrdata != NULL);
13201 
13202  /* the code below assumes that current activity is valid
13203  * if it turns out that we cannot ensure that, then we should change code
13204  */
13205  assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
13207 
13208  *cutoff = FALSE;
13209 
13210 #ifdef DEBUG_PROP
13211  SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
13212  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
13213  SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
13214 #endif
13215 
13216  if( SCIPexprIsIntegral(expr) )
13217  {
13218  /* apply integrality to new bounds
13219  * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
13220  */
13221  if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
13222  newbounds.inf = SCIPceil(scip, newbounds.inf);
13223  if( newbounds.sup < SCIP_INTERVAL_INFINITY )
13224  newbounds.sup = SCIPfloor(scip, newbounds.sup);
13225 #ifdef DEBUG_PROP
13226  SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
13227 #endif
13228  }
13229 
13231  {
13232  SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
13233 
13234  *cutoff = TRUE;
13235  return SCIP_OKAY;
13236  }
13237 
13238  /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
13239  if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
13240  {
13241  SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
13242 
13243  *cutoff = TRUE;
13244  return SCIP_OKAY;
13245  }
13246 
13247  /* tighten newbounds w.r.t. existing expr->propbounds or activity */
13248  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
13249  {
13250  /* if already having propbounds in expr, then tighten newbounds by propbounds */
13251  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
13252  }
13253  else
13254  {
13255  /* first time we have propbounds for expr in this propagation rounds:
13256  * intersect with activity (though don't let it become empty if very close intervals)
13257  */
13258  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
13259  }
13260 #ifdef DEBUG_PROP
13261  SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
13262 #endif
13263 
13264  /* check if the new bounds lead to an empty interval */
13266  {
13267  SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
13268 
13269  *cutoff = TRUE;
13270  return SCIP_OKAY;
13271  }
13272 
13273  /* if expr is not constant or variable, then store newbounds in expr->propbounds
13274  * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
13275  * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
13276  */
13277  if( SCIPexprGetNChildren(expr) > 0 )
13278  {
13279  ownerdata->propbounds = newbounds;
13280  ownerdata->propboundstag = conshdlrdata->curpropboundstag;
13281  }
13282 
13283  /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
13284  * propagation or update of auxvar bounds
13285  * TODO? if we first had a considerable tightening and then only get small tightenings under the same
13286  * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
13287  * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
13288  * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
13289  * one or should we not even update propbounds to newbounds if the update is small?
13290  */
13291  if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
13292  {
13293 #ifdef DEBUG_PROP
13294  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);
13295 #endif
13296  return SCIP_OKAY;
13297  }
13298 
13299  if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
13300  {
13301  /* add expression to propagation queue if not there yet and not var or constant and
13302  * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
13303  */
13304 #ifdef DEBUG_PROP
13305  SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
13306 #endif
13307  SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
13308  ownerdata->inpropqueue = TRUE;
13309  }
13310 
13311  /* update bounds on variable or auxiliary variable */
13312  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
13313 
13314  return SCIP_OKAY;
13315 }
13316 
13317 /** mark constraints that include this expression to be propagated again
13318  *
13319  * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
13320  * a change of variable bounds, e.g., because new information on the expression is available
13321  * that could potentially lead to tighter expression activity values.
13322  *
13323  * Note, that this call marks also constraints for propagation which only share some variable
13324  * with this expression.
13325  */
13327  SCIP* scip, /**< SCIP data structure */
13328  SCIP_EXPR* expr /**< expression to propagate again */
13329  )
13330 {
13331  SCIP_EXPRITER* it;
13332  SCIP_CONSDATA* consdata;
13333  SCIP_EXPR_OWNERDATA* ownerdata;
13334  int c;
13335 
13336  assert(scip != NULL);
13337  assert(expr != NULL);
13338 
13339  ownerdata = SCIPexprGetOwnerData(expr);
13340  assert(ownerdata != NULL);
13341 
13342  SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
13343 
13344  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13346 
13347  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
13348  {
13349  if( !SCIPisExprVar(scip, expr) )
13350  continue;
13351 
13352  ownerdata = SCIPexprGetOwnerData(expr);
13353  assert(ownerdata != NULL);
13354 
13355  for( c = 0; c < ownerdata->nconss; ++c )
13356  {
13357  consdata = SCIPconsGetData(ownerdata->conss[c]);
13358  assert(consdata != NULL);
13359  consdata->ispropagated = FALSE;
13360  }
13361  }
13362 
13363  SCIPfreeExpriter(&it);
13364 
13365  return SCIP_OKAY;
13366 }
13367 
13368 /** adds violation-branching score to an expression
13369  *
13370  * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
13371  * The expression must either be a variable expression or have an aux-variable.
13372  * In the latter case, branching on auxiliary variables must have been enabled.
13373  * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
13374  * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
13375  * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
13376  *
13377  * @see SCIPaddExprsViolScoreNonlinear()
13378  */
13380  SCIP* scip, /**< SCIP data structure */
13381  SCIP_EXPR* expr, /**< expression where to add branching score */
13382  SCIP_Real violscore /**< violation score to add to expression */
13383  )
13384 {
13385  SCIP_EXPR_OWNERDATA* ownerdata;
13386  SCIP_CONSHDLRDATA* conshdlrdata;
13387 
13388  assert(scip != NULL);
13389  assert(expr != NULL);
13390  assert(violscore >= 0.0);
13391 
13392  ownerdata = SCIPexprGetOwnerData(expr);
13393  assert(ownerdata != NULL);
13394 
13395  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13396  assert(conshdlrdata != NULL);
13397 
13398  /* if not allowing to branch on auxvars, then expr must be a var-expr */
13399  assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
13400  /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
13401  assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
13402 
13403  /* reset branching score if we are in a different enfo round */
13404  if( ownerdata->violscoretag != conshdlrdata->enforound )
13405  {
13406  ownerdata->violscoresum = violscore;
13407  ownerdata->violscoremax = violscore;
13408  ownerdata->nviolscores = 1;
13409  ownerdata->violscoretag = conshdlrdata->enforound;
13410  return;
13411  }
13412 
13413  ownerdata->violscoresum += violscore;
13414  if( violscore > ownerdata->violscoremax )
13415  ownerdata->violscoremax = violscore;
13416  ++ownerdata->nviolscores;
13417 }
13418 
13419 /** adds violation-branching score to a set of expressions, distributing the score among all the expressions
13420  *
13421  * Each expression must either be a variable expression or have an aux-variable.
13422  * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
13423  * variables present in `exprs`.
13424  */
13426  SCIP* scip, /**< SCIP data structure */
13427  SCIP_EXPR** exprs, /**< expressions where to add branching score */
13428  int nexprs, /**< number of expressions */
13429  SCIP_Real violscore, /**< violation score to add to expression */
13430  SCIP_SOL* sol, /**< current solution */
13431  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
13432  )
13433 {
13434  SCIP_EXPRITER* it;
13435  SCIP_EXPR** varexprs;
13436  SCIP_EXPR* e;
13437  int nvars;
13438  int varssize;
13439  int i;
13440 
13441  assert(exprs != NULL || nexprs == 0);
13442  assert(success != NULL);
13443 
13444  if( nexprs == 0 )
13445  {
13446  *success = FALSE;
13447  return SCIP_OKAY;
13448  }
13449 
13450  /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
13451  if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
13452  {
13453  addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
13454  return SCIP_OKAY;
13455  }
13456 
13457  /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
13458  nvars = 0;
13459  varssize = 5;
13460  SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
13461 
13462  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
13464 
13465  for( i = 0; i < nexprs; ++i )
13466  {
13467  for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
13468  {
13469  assert(e != NULL);
13470 
13471  if( SCIPisExprVar(scip, e) )
13472  {
13473  /* add variable expression to vars array */
13474  if( varssize == nvars )
13475  {
13476  varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
13477  SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
13478  }
13479  assert(varssize > nvars);
13480 
13481  varexprs[nvars++] = e;
13482  }
13483  }
13484  }
13485 
13486  SCIPfreeExpriter(&it);
13487 
13488  addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
13489 
13490  SCIPfreeBufferArray(scip, &varexprs);
13491 
13492  return SCIP_OKAY;
13493 }
13494 
13495 /** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
13497  SCIP_EXPR* expr /**< expression */
13498  )
13499 {
13500  SCIP_EXPR_OWNERDATA* ownerdata;
13501  SCIP_CONSHDLRDATA* conshdlrdata;
13502 
13503  assert(expr != NULL);
13504 
13505  ownerdata = SCIPexprGetOwnerData(expr);
13506  assert(ownerdata != NULL);
13507 
13508  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13509  assert(conshdlrdata != NULL);
13510 
13511  if( conshdlrdata->enforound != ownerdata->violscoretag )
13512  return 0.0;
13513 
13514  if( ownerdata->nviolscores == 0 )
13515  return 0.0;
13516 
13517  switch( conshdlrdata->branchscoreagg )
13518  {
13519  case 'a' :
13520  /* average */
13521  return ownerdata->violscoresum / ownerdata->nviolscores;
13522 
13523  case 'm' :
13524  /* maximum */
13525  return ownerdata->violscoremax;
13526 
13527  case 's' :
13528  /* sum */
13529  return ownerdata->violscoresum;
13530 
13531  default:
13532  SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
13533  SCIPABORT();
13534  return SCIP_INVALID;
13535  }
13536 }
13537 
13538 /** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
13539  *
13540  * @see SCIPexprGetDerivative()
13541  */
13543  SCIP* scip, /**< SCIP data structure */
13544  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
13545  SCIP_VAR* var /**< variable (needs to be in the expression) */
13546  )
13547 {
13548  SCIP_EXPR_OWNERDATA* ownerdata;
13549  SCIP_CONSHDLRDATA* conshdlrdata;
13550  SCIP_EXPR* varexpr;
13551 
13552  assert(scip != NULL);
13553  assert(expr != NULL);
13554  assert(var != NULL);
13555 
13556  /* return 0.0 for value expression */
13557  if( SCIPisExprValue(scip, expr) )
13558  {
13559  assert(SCIPexprGetDerivative(expr) == 0.0);
13560  return 0.0;
13561  }
13562 
13563  /* check if an error occurred during the last SCIPevalExprGradient() call */
13564  if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
13565  return SCIP_INVALID;
13566 
13567  ownerdata = SCIPexprGetOwnerData(expr);
13568  assert(ownerdata != NULL);
13569 
13570  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13571  assert(conshdlrdata != NULL);
13572 
13573  /* use variable to expressions mapping which is stored in the constraint handler data */
13574  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13575 
13576  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13577  assert(varexpr != NULL);
13578  assert(SCIPisExprVar(scip, varexpr));
13579 
13580  /* use difftag to decide whether the variable belongs to the expression */
13581  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
13582 }
13583 
13584 /** 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)
13585  *
13586  * @see SCIPexprGetBardot()
13587  */
13589  SCIP* scip, /**< SCIP data structure */
13590  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
13591  SCIP_VAR* var /**< variable (needs to be in the expression) */
13592  )
13593 {
13594  SCIP_EXPR_OWNERDATA* ownerdata;
13595  SCIP_CONSHDLRDATA* conshdlrdata;
13596  SCIP_EXPR* varexpr;
13597 
13598  assert(scip != NULL);
13599  assert(expr != NULL);
13600  assert(var != NULL);
13601 
13602  /* return 0.0 for value expression */
13603  if( SCIPisExprValue(scip, expr) )
13604  return 0.0;
13605 
13606  /* check if an error occurred during the last SCIPevalExprHessianDir() call */
13607  if( SCIPexprGetBardot(expr) == SCIP_INVALID )
13608  return SCIP_INVALID;
13609 
13610  ownerdata = SCIPexprGetOwnerData(expr);
13611  assert(ownerdata != NULL);
13612 
13613  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
13614  assert(conshdlrdata != NULL);
13615 
13616  /* use variable to expressions mapping which is stored in the constraint handler data;
13617  * if this fails it means that we are asking for the var's component of H*u for a var
13618  * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
13619  */
13620  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
13621 
13622  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
13623  assert(varexpr != NULL);
13624  assert(SCIPisExprVar(scip, varexpr));
13625 
13626  /* use difftag to decide whether the variable belongs to the expression */
13627  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
13628 }
13629 
13630 /** evaluates quadratic term in a solution w.r.t. auxiliary variables
13631  *
13632  * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
13633  */
13635  SCIP* scip, /**< SCIP data structure */
13636  SCIP_EXPR* expr, /**< quadratic expression */
13637  SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
13638  )
13639 {
13640  SCIP_Real auxvalue;
13641  int nlinexprs;
13642  SCIP_Real* lincoefs;
13643  SCIP_EXPR** linexprs;
13644  int nquadexprs;
13645  int nbilinexprs;
13646  int i;
13647 
13648  assert(scip != NULL);
13649  assert(expr != NULL);
13650 
13651  SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
13652 
13653  /* linear terms */
13654  for( i = 0; i < nlinexprs; ++i )
13655  {
13656  assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
13657  auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
13658  }
13659 
13660  /* quadratic terms */
13661  for( i = 0; i < nquadexprs; ++i )
13662  {
13663  SCIP_EXPR* quadexprterm;
13664  SCIP_Real lincoef;
13665  SCIP_Real sqrcoef;
13666  SCIP_Real solval;
13667 
13668  SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
13669 
13670  assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
13671 
13672  solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
13673  auxvalue += (lincoef + sqrcoef * solval) * solval;
13674  }
13675 
13676  /* bilinear terms */
13677  for( i = 0; i < nbilinexprs; ++i )
13678  {
13679  SCIP_EXPR* expr1;
13680  SCIP_EXPR* expr2;
13681  SCIP_Real coef;
13682 
13683  SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
13684 
13685  assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
13686  assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
13687  auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
13688  }
13689 
13690  return auxvalue;
13691 }
13692 
13693 /**@addtogroup PublicNlhdlrInterfaceMethods
13694  * @{
13695  */
13696 
13697 /** creates a nonlinear handler and includes it into the nonlinear constraint handler */
13699  SCIP* scip, /**< SCIP data structure */
13700  SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
13701  const char* name, /**< name of nonlinear handler (must not be NULL) */
13702  const char* desc, /**< description of nonlinear handler (can be NULL) */
13703  int detectpriority, /**< detection priority of nonlinear handler */
13704  int enfopriority, /**< enforcement priority of nonlinear handler */
13705  SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
13706  SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
13707  SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
13708  )
13709 {
13710  SCIP_CONSHDLR* conshdlr;
13711  SCIP_CONSHDLRDATA* conshdlrdata;
13712 
13713  assert(scip != NULL);
13714  assert(nlhdlr != NULL);
13715  assert(detect != NULL);
13716 
13717  /* find myself */
13718  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13719  if( conshdlr == NULL )
13720  {
13721  SCIPerrorMessage("nonlinear constraint handler not found");
13722  return SCIP_PLUGINNOTFOUND;
13723  }
13724 
13725  /* create nlhdlr */
13726  SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
13727 
13728  /* include into constraint handler */
13729  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13730  assert(conshdlrdata != NULL);
13731 
13732  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
13733 
13734  conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
13735  ++conshdlrdata->nnlhdlrs;
13736 
13737  /* sort nonlinear handlers by detection priority, in decreasing order
13738  * will happen in INIT, so only do when called late
13739  */
13740  if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
13741  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
13742 
13743  return SCIP_OKAY;
13744 }
13745 
13746 /** get number of nonlinear handler */
13748  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13749  )
13750 {
13751  SCIP_CONSHDLRDATA* conshdlrdata;
13752 
13753  assert(conshdlr != NULL);
13754 
13755  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13756  assert(conshdlrdata != NULL);
13757 
13758  return conshdlrdata->nnlhdlrs;
13759 }
13760 
13761 /** get nonlinear handlers */
13763  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13764  )
13765 {
13766  SCIP_CONSHDLRDATA* conshdlrdata;
13767 
13768  assert(conshdlr != NULL);
13769 
13770  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13771  assert(conshdlrdata != NULL);
13772 
13773  return conshdlrdata->nlhdlrs;
13774 }
13775 
13776 /** returns a nonlinear handler of a given name (or NULL if not found) */
13778  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13779  const char* name /**< name of nonlinear handler */
13780  )
13781 {
13782  SCIP_CONSHDLRDATA* conshdlrdata;
13783  int h;
13784 
13785  assert(conshdlr != NULL);
13786  assert(name != NULL);
13787 
13788  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13789  assert(conshdlrdata != NULL);
13790 
13791  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
13792  if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
13793  return conshdlrdata->nlhdlrs[h];
13794 
13795  return NULL;
13796 }
13797 
13798 /** gives expression data that a given nonlinear handler stored in an expression
13799  *
13800  * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
13801  */
13803  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
13804  SCIP_EXPR* expr /**< expression */
13805  )
13806 {
13807  SCIP_EXPR_OWNERDATA* ownerdata;
13808  int e;
13809 
13810  assert(nlhdlr != NULL);
13811  assert(expr != NULL);
13812 
13813  ownerdata = SCIPexprGetOwnerData(expr);
13814  assert(ownerdata != NULL);
13815 
13816  for( e = 0; e < ownerdata->nenfos; ++e )
13817  if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
13818  return ownerdata->enfos[e]->nlhdlrexprdata;
13819 
13820  return NULL;
13821 }
13822 
13823 /** @} */
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:768
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:4214
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2090
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:4067
SCIP_Longint SCIPgetExprNewSoltag(SCIP *scip)
Definition: scip_expr.c:1651
#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:8191
SCIP_EXPR_OWNERDATA * SCIPexprGetOwnerData(SCIP_EXPR *expr)
Definition: expr.c:3869
void SCIPexprSetIntegrality(SCIP_EXPR *expr, SCIP_Bool isintegral)
Definition: expr.c:4037
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
primal heuristic that tries a given solution
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:5209
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:1773
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:3298
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:8353
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:1485
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:1717
void SCIPsetLPFeastol(SCIP *scip, SCIP_Real newfeastol)
Definition: scip_lp.c:438
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2496
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:3808
#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:17919
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:3356
SCIP_Real SCIPgetVarPseudocostVal(SCIP *scip, SCIP_VAR *var, SCIP_Real solvaldelta)
Definition: scip_var.c:8820
#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:534
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:2851
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:17975
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:18282
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:17343
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
Definition: misc_rowprep.c:778
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1445
#define TABLE_EARLIEST_STAGE_NLHDLR
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1254
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:1804
SCIP_Real SCIPgetVarPseudocostCountCurrentRun(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition: scip_var.c:8956
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:10300
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:2351
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:4556
#define FALSE
Definition: def.h:96
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:4651
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3023
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:1280
int SCIPgetNBilinTermsNonlinear(SCIP_CONSHDLR *conshdlr)
char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:673
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:10764
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:4323
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:3141
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:3964
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:10287
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5326
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define CONSHDLR_SEPAFREQ
SCIP_SIDETYPE SCIProwprepGetSidetype(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:653
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:10012
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:3210
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:4619
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:1408
void SCIPsortDown(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5988
#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:2369
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:8363
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:125
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition: expr.c:4195
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:17304
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:8155
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18271
SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1667
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:2180
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:1463
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:2245
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8393
SCIP_RETCODE SCIPevalExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
Definition: scip_expr.c:1634
#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:3372
SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:633
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:7443
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:8182
static SCIP_RETCODE createAuxVar(SCIP *scip, SCIP_EXPR *expr)
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3818
SCIP_DIALOG * SCIPgetRootDialog(SCIP *scip)
Definition: scip_dialog.c:157
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17929
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:1862
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:3980
SCIP_RETCODE SCIPcreateClock(SCIP *scip, SCIP_CLOCK **clck)
Definition: scip_timing.c:76
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:613
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:258
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition: expr.c:3882
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:4184
#define CONSHDLR_ENFOPRIORITY
static SCIP_DECL_CONSINITLP(consInitlpNonlinear)
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2778
SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
Definition: expr.c:3908
SCIP_Bool SCIProwprepIsLocal(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:663
#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:17143
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:3482
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:654
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:8094
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:8721
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1441
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8313
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17260
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:5138
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3057
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4204
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:4114
#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:2613
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:2080
SCIP_RETCODE SCIPaddExprNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_EXPR *expr, SCIP_Real coef)
SCIP_Real SCIPexprGetBardot(SCIP_EXPR *expr)
Definition: expr.c:3936
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:1247
SCIP_Longint SCIPexprGetDiffTag(SCIP_EXPR *expr)
Definition: expr.c:3951
#define DIALOG_NAME
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1452
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
Definition: misc_rowprep.c:567
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:393
#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:2577
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:3895
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define consGetDiveBdChgsNonlinear
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8333
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:949
SCIP_VAR ** SCIProwprepGetModifiedVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:693
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:4599
SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2311
#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:683
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:664
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:5040
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:8212
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:1317
SCIP_Real SCIPgetClockTime(SCIP *scip, SCIP_CLOCK *clck)
Definition: scip_timing.c:319
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition: var.c:17565
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:1416
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_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10865
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:361
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8114
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11950
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:8223
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:1379
#define CONSHDLR_NEEDSCONS
SCIP_RETCODE SCIPgetExprNVars(SCIP *scip, SCIP_EXPR *expr, int *nvars)
Definition: scip_expr.c:2042
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:8293
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8263
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17767
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:4027
SCIP_RETCODE SCIPcomputeExprIntegrality(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1999
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:17630
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition: expr.c:3831
Constraint handler for linear constraints in their most general form, .
static SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2228
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2557
SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1474
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:2045
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:10034
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:17448
constant value expression handler
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2295
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2000
#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:2325
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:8201
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:3388
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:4933
#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:3482
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:1676
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8124
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:643
#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
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:1430
#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:4157
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1955
int SCIPgetNNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17379
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:1220
#define SCIP_Real
Definition: def.h:186
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8343
#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:3990
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:8283
#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:8273
SCIP_Bool SCIPnlhdlrHasEstimate(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:250
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2206
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:17599
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:17425
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:69
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:17985
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
Definition: misc_rowprep.c:890
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:3105
#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:3230
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:365
static SCIP_DECL_CONSPARSE(consParseNonlinear)
SCIP_INTERVAL SCIPgetExprBoundsNonlinear(SCIP *scip, SCIP_EXPR *expr)
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition: lp.c:17132
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:17451
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:3798
#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:17107
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:1032
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:623
#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)